[scripts] Going to utf-8

This commit is contained in:
Pierre-Elliott Bécue 2013-05-04 19:19:36 +02:00
parent c4a19a88ed
commit a1bf0a4547
54 changed files with 676 additions and 573 deletions

View file

@ -1,21 +1,21 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
# Copyright (C) Stéphane Glondu, Alexandre Bos, Michel Blockelet # Copyright (C) Stéphane Glondu, Alexandre Bos, Michel Blockelet
# Licence : GPLv2 # Licence : GPLv2
u"""Ce script permet au secrétaire de repérer plus facilement les membres u"""Ce script permet au secrétaire de repérer plus facilement les membres
actifs qui n'ont pas signé la charte du même nom. actifs qui n'ont pas signé la charte du même nom.
Utilisation : Utilisation :
%(prog)s {liste|modif|spam} [--debug <adresse>] %(prog)s {liste|modif|spam} [--debug <adresse>]
L'unique option est : L'unique option est :
--debug <adresse> envoyer tous les mails à l'<adresse> indiquée, plutôt --debug <adresse> envoyer tous les mails à l'<adresse> indiquée, plutôt
qu'aux vrais destinataires qu'aux vrais destinataires
Les commandes sont : Les commandes sont :
* liste énumérer les membres n'ayant pas signé la charte * liste énumérer les membres n'ayant pas signé la charte
* modif modifier les membres actifs n'ayant pas signé la charte * modif modifier les membres actifs n'ayant pas signé la charte
* spam envoie des mails de rappel pour les chartes * spam envoie des mails de rappel pour les chartes
""" """
@ -29,7 +29,7 @@ from email_tools import send_email, parse_mail_template
# Fonctions d'affichage # Fonctions d'affichage
from affich_tools import coul, tableau, prompt, cprint from affich_tools import coul, tableau, prompt, cprint
# Importation de la base de données # Importation de la base de données
from ldap_crans import crans_ldap, ann_scol from ldap_crans import crans_ldap, ann_scol
db = crans_ldap() db = crans_ldap()
@ -44,12 +44,12 @@ if __name__ == '__main__':
sys.argv.pop() sys.argv.pop()
if debug: if debug:
cprint(u'Mode debug, tous les mails seront envoyés à %s.' % debug) cprint(u'Mode debug, tous les mails seront envoyés à %s.' % debug)
def _controle_interactif_adherents(liste): def _controle_interactif_adherents(liste):
""" """
Contrôle interactif des adhérents de la liste. Contrôle interactif des adhérents de la liste.
Retourne (nb_OK, nb_pas_OK). Retourne (nb_OK, nb_pas_OK).
""" """
@ -57,10 +57,10 @@ def _controle_interactif_adherents(liste):
if restant == 0: if restant == 0:
return 0, 0 return 0, 0
cprint(u'\nContrôle des membre actifs' , 'cyan') cprint(u'\nContrôle des membre actifs' , 'cyan')
cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).") cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).")
cprint(u"Une autre réponse entraîne l'interruption du processus.") cprint(u"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).") cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
cprint(u"") cprint(u"")
nb = 0 nb = 0
@ -81,7 +81,7 @@ def _controle_interactif_adherents(liste):
modifiable.charteMA(True) modifiable.charteMA(True)
cprint(modifiable.save()) cprint(modifiable.save())
else: else:
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge') cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
elif ok == 'n': elif ok == 'n':
if a.charteMA() == True: if a.charteMA() == True:
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0] modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
@ -89,16 +89,16 @@ def _controle_interactif_adherents(liste):
modifiable.charteMA(False) modifiable.charteMA(False)
cprint(modifiable.save()) cprint(modifiable.save())
else: else:
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge') cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
else: else:
cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge') cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge')
break break
return nb, len(liste)-nb return nb, len(liste)-nb
def liste_charte_nok(): def liste_charte_nok():
"""Retourne la liste des membres actifs qui n'ont pas signé la charte.""" """Retourne la liste des membres actifs qui n'ont pas signé la charte."""
liste_actifs = db.search('droits=*')['adherent'] liste_actifs = db.search('droits=*')['adherent']
liste_nok = [] liste_nok = []
for adh in liste_actifs: for adh in liste_actifs:
@ -110,25 +110,25 @@ def liste_charte_nok():
def controle_interactif(): def controle_interactif():
""" """
Procédure interactive de contrôle des chartes de membres actifs. Procédure interactive de contrôle des chartes de membres actifs.
""" """
todo_list = liste_charte_nok() todo_list = liste_charte_nok()
# Tri de la liste des adhérents selon nom, prénom # Tri de la liste des adhérents selon nom, prénom
# Ça peut se faire plus facilement en Python 2.4 avec l'argument key # Ça peut se faire plus facilement en Python 2.4 avec l'argument key
todo_list.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom()))) todo_list.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom())))
# Zou ! # Zou !
ok, nok = _controle_interactif_adherents(todo_list) ok, nok = _controle_interactif_adherents(todo_list)
cprint(u'\nRécapitulatif des nouveaux contrôles :', 'violet') cprint(u'\nRécapitulatif des nouveaux contrôles :', 'violet')
liste = [[u'membres actifs', str(ok), str(nok)]] liste = [[u'membres actifs', str(ok), str(nok)]]
cprint(tableau(liste, cprint(tableau(liste,
titre = [u'Catégorie', u'OK', u'pas OK'], titre = [u'Catégorie', u'OK', u'pas OK'],
largeur = [15, 10, 10])) largeur = [15, 10, 10]))
def spammer(): def spammer():
# On envoie un mail à chacun des membres actifs qui n'ont pas donné le papier # On envoie un mail à chacun des membres actifs qui n'ont pas donné le papier
todo_list = liste_charte_nok() todo_list = liste_charte_nok()
if todo_list: if todo_list:
@ -144,10 +144,10 @@ def spammer():
print to print to
if not debug: if not debug:
data = config.mails.txt_charte_MA % {'From' : u"ca@crans.org", 'To' : to} data = config.mails.txt_charte_MA % {'From' : u"ca@crans.org", 'To' : to}
connexion.sendmail("ca@crans.org",to,data.encode('iso-8859-15')) connexion.sendmail("ca@crans.org",to,data.encode('utf-8'))
def __usage(message=None): def __usage(message=None):
""" Comment ça marche ? """ """ Comment ça marche ? """
cprint(__doc__ % { 'prog': sys.argv[0] }) cprint(__doc__ % { 'prog': sys.argv[0] })
if message: if message:
cprint(message) cprint(message)
@ -161,7 +161,7 @@ if __name__ == '__main__' :
elif sys.argv[1] == 'liste': elif sys.argv[1] == 'liste':
if len(sys.argv) != 2: if len(sys.argv) != 2:
__usage(u'Mauvaise utilisation de liste') __usage(u'Mauvaise utilisation de liste')
print "Liste des membres actifs n'ayant pas signé la charte :" print "Liste des membres actifs n'ayant pas signé la charte :"
for adh in liste_charte_nok(): for adh in liste_charte_nok():
print adh.Nom() print adh.Nom()
elif sys.argv[1] == 'modif': elif sys.argv[1] == 'modif':

View file

@ -1,43 +1,43 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
# Copyright (C) Stéphane Glondu # Copyright (C) Stéphane Glondu
# Licence : GPLv2 # Licence : GPLv2
u"""Ce script permet au trésorier de repérer plus facilement les papiers que u"""Ce script permet au trésorier de repérer plus facilement les papiers que
les câbleurs n'ont pas encore rendus. les câbleurs n'ont pas encore rendus.
Utilisations possibles : Utilisations possibles :
* %(prog)s OPTIONS {paiement|carte|list} * %(prog)s OPTIONS {paiement|carte|list}
* %(prog)s OPTIONS mail <liste> * %(prog)s OPTIONS mail <liste>
Les options sont: Les options sont:
-d, --debug <adresse> envoyer tous les mails à l'<adresse> indiquée, plutôt -d, --debug <adresse> envoyer tous les mails à l'<adresse> indiquée, plutôt
qu'aux vrais destinataires qu'aux vrais destinataires
-h, --help affiche ce message -h, --help affiche ce message
-t, --tri <champ> trier suivant ce champ. Les champs possibles sont: -t, --tri <champ> trier suivant ce champ. Les champs possibles sont:
id, nom, cableur ou date. Le défaut est ``nom'' id, nom, cableur ou date. Le défaut est ``nom''
-i, --inverse trier par ordre inverse -i, --inverse trier par ordre inverse
Les commandes sont : Les commandes sont :
* paiement contrôle interactif des nouvelles (-)adhésions * paiement contrôle interactif des nouvelles (-)adhésions
* carte contrôle interactif des nouvelles cartes d'étudiant * carte contrôle interactif des nouvelles cartes d'étudiant
* list affiche le récapitulatif des papiers manquants * list affiche le récapitulatif des papiers manquants
* mail <liste> envoyer les mails de rappel aux câbleurs dont le * mail <liste> envoyer les mails de rappel aux câbleurs dont le
login est dans la <liste>, 'bureau' désignant le mail login est dans la <liste>, 'bureau' désignant le mail
récapitulatif envoyé à bureau ; si la liste est vide récapitulatif envoyé à bureau ; si la liste est vide
tous les mails nécessaires seront envoyés tous les mails nécessaires seront envoyés
* help affiche ce message * help affiche ce message
Le modèle du mail envoyé aux câbleurs est lu sur l'entrée standard (typiquement Le modèle du mail envoyé aux câbleurs est lu sur l'entrée standard (typiquement
via une redirection). Les trois premières lignes doivent être : via une redirection). Les trois premières lignes doivent être :
Encoding: <encodage du fichier> Encoding: <encodage du fichier>
Subject: <sujet du mail> Subject: <sujet du mail>
<ligne vide> <ligne vide>
Le reste est le corps du message. Il doit contenir une occurrence de '%%s' qui Le reste est le corps du message. Il doit contenir une occurrence de '%%s' qui
sera remplacée par la liste des papiers manquants. sera remplacée par la liste des papiers manquants.
Le mail récapitulatif envoyé à bureau est immuable.""" Le mail récapitulatif envoyé à bureau est immuable."""
import sys, os, re, getopt import sys, os, re, getopt
@ -46,21 +46,21 @@ sys.path.append('/usr/scripts/gestion')
# Fonctions d'affichage # Fonctions d'affichage
from affich_tools import coul, tableau, prompt, cprint from affich_tools import coul, tableau, prompt, cprint
# Importation de la base de données # Importation de la base de données
from ldap_crans import crans_ldap, ann_scol from ldap_crans import crans_ldap, ann_scol
db = crans_ldap() db = crans_ldap()
# Détermination de l'uid du câbleur # Détermination de l'uid du câbleur
from user_tests import getuser from user_tests import getuser
uid = getuser() uid = getuser()
if not uid : if not uid :
cprint(u"Impossible de déterminer l'utilisateur !") cprint(u"Impossible de déterminer l'utilisateur !")
sys.exit(1) sys.exit(1)
cableur = db.search('uid=%s' % uid)['adherent'][0] cableur = db.search('uid=%s' % uid)['adherent'][0]
# Vérification des droits # Vérification des droits
if u'Tresorier' not in cableur.droits(): if u'Tresorier' not in cableur.droits():
cprint(u"Il faut etre tresorier pour exécuter ce script !") cprint(u"Il faut etre tresorier pour exécuter ce script !")
sys.exit(1) sys.exit(1)
# Lors des tests, on m'envoie tous les mails ! # Lors des tests, on m'envoie tous les mails !
@ -77,19 +77,19 @@ if gethostname().split(".")[0] == 'egon':
def _controle_interactif_adherents(liste, quoi): def _controle_interactif_adherents(liste, quoi):
""" """
Contrôle interactif des adhérents de la liste (quoi = p ou c). Contrôle interactif des adhérents de la liste (quoi = p ou c).
Retourne (nb_OK, nb_pas_OK). Retourne (nb_OK, nb_pas_OK).
""" """
if quoi not in 'pc': raise ValueError if quoi not in 'pc': raise ValueError
explicite = {'p': u'du paiement', 'c': u"de la carte d'étudiant"}[quoi] explicite = {'p': u'du paiement', 'c': u"de la carte d'étudiant"}[quoi]
restant = len(liste) restant = len(liste)
if restant == 0: if restant == 0:
return 0, 0 return 0, 0
cprint(u'\nContrôle %s des adhérents' % explicite, 'cyan') cprint(u'\nContrôle %s des adhérents' % explicite, 'cyan')
cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).") cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).")
cprint(u"Une autre réponse entraîne l'interruption du processus.") cprint(u"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).") cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
cprint(u"") cprint(u"")
nb = 0 nb = 0
@ -104,9 +104,9 @@ def _controle_interactif_adherents(liste, quoi):
cprint(modifiable.save()) cprint(modifiable.save())
nb += 1 nb += 1
else: else:
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge') cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
elif ok != 'n': elif ok != 'n':
cprint(u'Arrêt du contrôle %s des adhérents' % explicite, 'rouge') cprint(u'Arrêt du contrôle %s des adhérents' % explicite, 'rouge')
break break
return nb, len(liste)-nb return nb, len(liste)-nb
@ -114,16 +114,16 @@ def _controle_interactif_adherents(liste, quoi):
def _controle_interactif_clubs(liste): def _controle_interactif_clubs(liste):
""" """
Contrôle interactif des clubs de la liste (uniquement la charte). Contrôle interactif des clubs de la liste (uniquement la charte).
Retourne (nb_OK, nb_pas_OK). Retourne (nb_OK, nb_pas_OK).
""" """
restant = len(liste) restant = len(liste)
if restant == 0: if restant == 0:
return 0, 0 return 0, 0
cprint(u'\nContrôle de la charte des clubs', 'cyan') cprint(u'\nContrôle de la charte des clubs', 'cyan')
cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n'.") cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n'.")
cprint(u"Une autre réponse entraîne l'interruption du processus.") cprint(u"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom (cid).") cprint(u"Le format est [nb_restant] Nom (cid).")
cprint(u"") cprint(u"")
@ -139,17 +139,17 @@ def _controle_interactif_clubs(liste):
cprint(modifiable.save()) cprint(modifiable.save())
nb += 1 nb += 1
else: else:
cprint(u'Club %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge') cprint(u'Club %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
elif ok != 'n': elif ok != 'n':
cprint(u'Arrêt du contrôle de la charte des clubs', 'rouge') cprint(u'Arrêt du contrôle de la charte des clubs', 'rouge')
break break
return nb, len(liste)-nb return nb, len(liste)-nb
def qui(historique, quoi): def qui(historique, quoi):
""" """
Recherche le câbleur qui a effectué la dernière modification quoi Recherche le câbleur qui a effectué la dernière modification quoi
dans l'historique, ou qui a inscrit l'adhérent. dans l'historique, ou qui a inscrit l'adhérent.
Retourne le couple (date, cableur) ou ('_inconnu_', '_inconnu_'). Retourne le couple (date, cableur) ou ('_inconnu_', '_inconnu_').
""" """
regexp = re.compile(r'^([^,]*), ([^ :]*)') regexp = re.compile(r'^([^,]*), ([^ :]*)')
@ -166,13 +166,13 @@ def qui(historique, quoi):
def controle_interactif(quoi): def controle_interactif(quoi):
""" """
Procédure interactive de contrôle des paiements/chartes (quoi=p) et cartes (quoi=c). Procédure interactive de contrôle des paiements/chartes (quoi=p) et cartes (quoi=c).
""" """
if quoi not in 'pc': raise ValueError if quoi not in 'pc': raise ValueError
todo_list = db.search('%s=%d&controle!=*%s*' todo_list = db.search('%s=%d&controle!=*%s*'
% ({'p': 'paiement', 'c': 'carteEtudiant'}[quoi], ann_scol, quoi)) % ({'p': 'paiement', 'c': 'carteEtudiant'}[quoi], ann_scol, quoi))
# Tri de la liste des adhérents selon nom, prénom # Tri de la liste des adhérents selon nom, prénom
todo_list['adherent'].sort(key = lambda x: (x.nom(), x.prenom())) todo_list['adherent'].sort(key = lambda x: (x.nom(), x.prenom()))
if trier_par == 'id': if trier_par == 'id':
@ -183,7 +183,7 @@ def controle_interactif(quoi):
champ = { 'date': 0, 'cableur': 1 }[trier_par] champ = { 'date': 0, 'cableur': 1 }[trier_par]
todo_list['adherent'].sort(key = lambda x: qui(x.historique(), r'paiement')[champ]) todo_list['adherent'].sort(key = lambda x: qui(x.historique(), r'paiement')[champ])
# Traitement des adhérents # Traitement des adhérents
oka, noka = _controle_interactif_adherents(todo_list['adherent'], quoi) oka, noka = _controle_interactif_adherents(todo_list['adherent'], quoi)
if quoi == 'p': if quoi == 'p':
@ -193,18 +193,18 @@ def controle_interactif(quoi):
# Traitement des clubs (uniquement la charte) # Traitement des clubs (uniquement la charte)
okc, nokc =_controle_interactif_clubs(todo_list['club']) okc, nokc =_controle_interactif_clubs(todo_list['club'])
cprint(u'\nRécapitulatif des nouveaux contrôles +%s :' % quoi, 'violet') cprint(u'\nRécapitulatif des nouveaux contrôles +%s :' % quoi, 'violet')
liste = [[u'adhérents', str(oka), str(noka)]] liste = [[u'adhérents', str(oka), str(noka)]]
if quoi == 'p': if quoi == 'p':
liste.append([u'clubs', str(okc), str(nokc)]) liste.append([u'clubs', str(okc), str(nokc)])
cprint(tableau(liste, cprint(tableau(liste,
titre = [u'Catégorie', u'OK', u'pas OK'], titre = [u'Catégorie', u'OK', u'pas OK'],
largeur = [15, 10, 10])) largeur = [15, 10, 10]))
def formater_pour_cableur(liste): def formater_pour_cableur(liste):
""" """
Formate la liste d'adhérents ou de clubs avec les dates correspondantes. Formate la liste d'adhérents ou de clubs avec les dates correspondantes.
liste est une liste de couples (date, objet). liste est une liste de couples (date, objet).
""" """
lignes = [] lignes = []
@ -231,8 +231,8 @@ def formater_pour_cableur(liste):
def formater_pour_bureau(dico): def formater_pour_bureau(dico):
""" """
Formate la liste d'adhérents ou de clubs avec les câbleurs correspondantes Formate la liste d'adhérents ou de clubs avec les câbleurs correspondantes
pour le mail récapitulatif envoyé à bureau. pour le mail récapitulatif envoyé à bureau.
""" """
lignes = [] lignes = []
total = 0 total = 0
@ -253,15 +253,15 @@ def formater_pour_bureau(dico):
if tri_inverse: lignes.reverse() if tri_inverse: lignes.reverse()
return tableau(lignes, return tableau(lignes,
titre = [u'id', u'Nom', u'Câbleur', u'Date'], titre = [u'id', u'Nom', u'Câbleur', u'Date'],
largeur = [6, 40, 18, 18], largeur = [6, 40, 18, 18],
alignement = ['d', 'c', 'c', 'c']) + u'\nTotal : %d' % total alignement = ['d', 'c', 'c', 'c']) + u'\nTotal : %d' % total
def chercher_cableurs(liste, quoi): def chercher_cableurs(liste, quoi):
""" """
Renvoie un dictionnaire cableur->adherents à partir de liste, quoi Renvoie un dictionnaire cableur->adherents à partir de liste, quoi
désigne le champ qui sera recherché dans l'historique. désigne le champ qui sera recherché dans l'historique.
""" """
resultat = {} resultat = {}
@ -275,21 +275,21 @@ def chercher_cableurs(liste, quoi):
from email_tools import send_email, parse_mail_template from email_tools import send_email, parse_mail_template
# Mise en application du mémorable cours de Fred sur les objets :-) # Mise en application du mémorable cours de Fred sur les objets :-)
class ControleMailer: class ControleMailer:
def __init__(self): def __init__(self):
# Recherche des câbleurs possédant des cotisations/chartes # Recherche des câbleurs possédant des cotisations/chartes
todo_list = db.search('paiement=%d&controle!=*p*' % ann_scol) todo_list = db.search('paiement=%d&controle!=*p*' % ann_scol)
self._paiements = chercher_cableurs(todo_list['adherent'], r'(paiement|controle.*\+k)') self._paiements = chercher_cableurs(todo_list['adherent'], r'(paiement|controle.*\+k)')
self._chartes = chercher_cableurs(todo_list['club'], 'paiement') self._chartes = chercher_cableurs(todo_list['club'], 'paiement')
# Recherche des câbleurs possédant des cartes d'étudiant # Recherche des câbleurs possédant des cartes d'étudiant
todo_list = db.search('carteEtudiant=%d&controle!=*c*' % ann_scol) todo_list = db.search('carteEtudiant=%d&controle!=*c*' % ann_scol)
self._cartes = chercher_cableurs(todo_list['adherent'], 'carteEtudiant') self._cartes = chercher_cableurs(todo_list['adherent'], 'carteEtudiant')
# Récupère tous les câbleurs qui doivent quelque chose # Récupère tous les câbleurs qui doivent quelque chose
cableurs = {} cableurs = {}
for a in self._paiements.keys(): for a in self._paiements.keys():
if a != '_inconnu_': cableurs[a] = None if a != '_inconnu_': cableurs[a] = None
@ -299,14 +299,14 @@ class ControleMailer:
if a != '_inconnu_': cableurs[a] = None if a != '_inconnu_': cableurs[a] = None
self._cableurs = cableurs.keys() self._cableurs = cableurs.keys()
# Vérification de l'alias pour l'expéditeur # Vérification de l'alias pour l'expéditeur
if u'tresorier' in cableur.alias(): if u'tresorier' in cableur.alias():
self._sender = u'%s <tresorier@crans.org>' % cableur.Nom() self._sender = u'%s <tresorier@crans.org>' % cableur.Nom()
else: else:
self._sender = u'%s <%s@crans.org>' % (cableur.Nom(), self._sender = u'%s <%s@crans.org>' % (cableur.Nom(),
cableur.canonical_alias() or cableur.mail()) cableur.canonical_alias() or cableur.mail())
# Se connecte au serveur SMTP par défaut # Se connecte au serveur SMTP par défaut
from smtplib import SMTP from smtplib import SMTP
self._server = SMTP() self._server = SMTP()
self._server.connect() self._server.connect()
@ -317,47 +317,47 @@ class ControleMailer:
def recapitulatif(self): def recapitulatif(self):
""" """
Renvoie le récapitulatif pour le bureau. Renvoie le récapitulatif pour le bureau.
""" """
msg = u'' msg = u''
if self._paiements: if self._paiements:
msg += u"Fiches d'adhésion et cotisations et/ou caution des adhérents :\n" msg += u"Fiches d'adhésion et cotisations et/ou caution des adhérents :\n"
msg += formater_pour_bureau(self._paiements) + '\n\n' msg += formater_pour_bureau(self._paiements) + '\n\n'
if self._chartes: if self._chartes:
msg += u"Chartes signées des clubs :\n" msg += u"Chartes signées des clubs :\n"
msg += formater_pour_bureau(self._chartes) + '\n\n' msg += formater_pour_bureau(self._chartes) + '\n\n'
if self._cartes: if self._cartes:
msg += u"Carte d'étudiant des adhérents :\n" msg += u"Carte d'étudiant des adhérents :\n"
msg += formater_pour_bureau(self._cartes) + '\n\n' msg += formater_pour_bureau(self._cartes) + '\n\n'
return msg.strip() return msg.strip()
def mail_bureau(self): def mail_bureau(self):
""" """
Envoie le mail récapitulatif à bureau (s'il y a qqch à envoyer). Envoie le mail récapitulatif à bureau (s'il y a qqch à envoyer).
""" """
msg = self.recapitulatif() msg = self.recapitulatif()
if msg: if msg:
msg += u"\n\n-- \nScript exécuté par %s\n" % cableur.Nom() msg += u"\n\n-- \nScript exécuté par %s\n" % cableur.Nom()
send_email(self._sender, send_email(self._sender,
u"Bureau <bureau@crans.org>", u"Bureau <bureau@crans.org>",
u"Récapitulatif des papiers manquants", u"Récapitulatif des papiers manquants",
msg, msg,
server = self._server, server = self._server,
debug = debug) debug = debug)
return coul(u'Mail envoyé à bureau avec succès !', 'vert') return coul(u'Mail envoyé à bureau avec succès !', 'vert')
else: else:
return coul(u'Tout est à jour, aucun mail envoyé.', 'vert') return coul(u'Tout est à jour, aucun mail envoyé.', 'vert')
def mail_cableurs(self, subject, body, liste=None): def mail_cableurs(self, subject, body, liste=None):
""" """
Envoie un mail aux câbleurs concernés qui figurent dans la liste. Envoie un mail aux câbleurs concernés qui figurent dans la liste.
Si liste vaut None, envoie un mail à tous les câbleurs concernés. Si liste vaut None, envoie un mail à tous les câbleurs concernés.
Les arguments subject, body permettent de personnaliser (un peu) Les arguments subject, body permettent de personnaliser (un peu)
le mail qui sera envoyé. le mail qui sera envoyé.
""" """
nb = 0 nb = 0
if liste == None: if liste == None:
@ -367,15 +367,15 @@ class ControleMailer:
msg = u'' msg = u''
if self._paiements.has_key(c): if self._paiements.has_key(c):
msg += u"Fiches d'adhésion, cotisations et/ou caution des adhérents :\n" msg += u"Fiches d'adhésion, cotisations et/ou caution des adhérents :\n"
msg += formater_pour_cableur(self._paiements[c]) + '\n\n' msg += formater_pour_cableur(self._paiements[c]) + '\n\n'
if self._chartes.has_key(c): if self._chartes.has_key(c):
msg += u"Chartes signées des clubs :\n" msg += u"Chartes signées des clubs :\n"
msg += formater_pour_cableur(self._chartes[c]) + '\n\n' msg += formater_pour_cableur(self._chartes[c]) + '\n\n'
if self._cartes.has_key(c): if self._cartes.has_key(c):
msg += u"Carte d'étudiant des adhérents :\n" msg += u"Carte d'étudiant des adhérents :\n"
msg += formater_pour_cableur(self._cartes[c]) + '\n\n' msg += formater_pour_cableur(self._cartes[c]) + '\n\n'
if msg: if msg:
@ -388,11 +388,11 @@ class ControleMailer:
debug = debug) debug = debug)
nb += 1 nb += 1
return coul(u'%d mail(s) envoyé(s) aux câbleurs avec succès !' % nb, 'vert') return coul(u'%d mail(s) envoyé(s) aux câbleurs avec succès !' % nb, 'vert')
def __usage(message=None): def __usage(message=None):
""" Comment ça marche ? """ """ Comment ça marche ? """
cprint(__doc__ % { 'prog': sys.argv[0] }) cprint(__doc__ % { 'prog': sys.argv[0] })
if message: if message:
cprint(message) cprint(message)
@ -412,7 +412,7 @@ if __name__ == '__main__' :
elif opt in [ '-d', '--debug' ]: elif opt in [ '-d', '--debug' ]:
debug = val debug = val
cprint(u'Mode debug, tous les mails seront envoyés à %s.' % debug) cprint(u'Mode debug, tous les mails seront envoyés à %s.' % debug)
elif opt in [ '-t', '--tri' ]: elif opt in [ '-t', '--tri' ]:
if val in [ 'id', 'nom', 'cableur', 'date' ]: if val in [ 'id', 'nom', 'cableur', 'date' ]:
@ -424,7 +424,7 @@ if __name__ == '__main__' :
tri_inverse = True tri_inverse = True
else: else:
__usage("option inconnue « %s »'" % opt) __usage("option inconnue « %s »'" % opt)
if len(arg) == 0 or arg[0] == 'help': if len(arg) == 0 or arg[0] == 'help':
__usage() __usage()
@ -456,14 +456,14 @@ if __name__ == '__main__' :
bureau = True bureau = True
cableurs = mailer._cableurs cableurs = mailer._cableurs
if cableurs: if cableurs:
cprint(u'Des mails vont être envoyés aux câbleurs, lecture du modèle...') cprint(u'Des mails vont être envoyés aux câbleurs, lecture du modèle...')
subject, body = parse_mail_template(sys.stdin) subject, body = parse_mail_template(sys.stdin)
try: try:
body % u'' body % u''
except TypeError: except TypeError:
cprint(u"Le format du modèle n'est pas correct, arrêt.") cprint(u"Le format du modèle n'est pas correct, arrêt.")
sys.exit(1) sys.exit(1)
cprint(u'Modèle OK, on envoie les mails...') cprint(u'Modèle OK, on envoie les mails...')
cprint(mailer.mail_cableurs(subject, body, cableurs)) cprint(mailer.mail_cableurs(subject, body, cableurs))
if bureau: if bureau:
cprint(mailer.mail_bureau()) cprint(mailer.mail_bureau())

View file

@ -47,7 +47,7 @@ if u'Tresorier' not in cableur.droits():
dlg = dialog.Dialog() dlg = dialog.Dialog()
dlg.setBackgroundTitle('Tresorerie') dlg.setBackgroundTitle('Tresorerie')
encoding = sys.stdin.encoding or 'ISO-8859-15' encoding = sys.stdin.encoding or 'UTF-8'
######################################################################## ########################################################################
# Retrait des accents # Retrait des accents

View file

@ -1,20 +1,20 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
# Copyright (C) Stéphane Glondu, Alexandre Bos # Copyright (C) Stéphane Glondu, Alexandre Bos
# Licence : GPLv2 # Licence : GPLv2
__doc__ = u"""Ce script permet de faire le menages parmis les câbleurs qui ne __doc__ = u"""Ce script permet de faire le menages parmis les câbleurs qui ne
sont plus sur le campus, ie ceux qui ne sont plus à jour de cotisation. sont plus sur le campus, ie ceux qui ne sont plus à jour de cotisation.
Utilisation : Utilisation :
%(prog)s {lister|radier} [--debug <adresse>] %(prog)s {lister|radier} [--debug <adresse>]
Les commandes sont : Les commandes sont :
* lister afficher la liste des câbleurs succeptibles d'être * lister afficher la liste des câbleurs succeptibles d'être
radiés radiés
* radier selectionner, parmis eux, les cableurs que l'on * radier selectionner, parmis eux, les cableurs que l'on
souhaite radier souhaite radier
""" """
@ -28,23 +28,23 @@ from email_tools import send_email, parse_mail_template
# Fonctions d'affichage # Fonctions d'affichage
from affich_tools import coul, tableau, prompt, cprint from affich_tools import coul, tableau, prompt, cprint
# Importation de la base de données # Importation de la base de données
from ldap_crans import crans_ldap, ann_scol from ldap_crans import crans_ldap, ann_scol
db = crans_ldap() db = crans_ldap()
def _controle_interactif_adherents(liste): def _controle_interactif_adherents(liste):
""" """
Demande ce qu'il faut faire à chaque fois Demande ce qu'il faut faire à chaque fois
""" """
restant = len(liste) restant = len(liste)
if restant == 0: if restant == 0:
return 0, 0 return 0, 0
cprint(u'\nRadiation des câbleurs fantômes' , 'cyan') cprint(u'\nRadiation des câbleurs fantômes' , 'cyan')
cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).") cprint(u"Pour chaque entrée, il faut taper 'o' ou 'n' (défaut=n).")
cprint(u"Une autre réponse entraîne l'interruption du processus.") cprint(u"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).") cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
cprint(u"") cprint(u"")
nb = 0 nb = 0
@ -58,9 +58,9 @@ def _controle_interactif_adherents(liste):
modifiable.droits([]) modifiable.droits([])
cprint(modifiable.save()) cprint(modifiable.save())
else: else:
cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge') cprint(u'Adhérent %s locké, réessayer plus tard' % modifiable.Nom(), 'rouge')
elif ok != 'n': elif ok != 'n':
cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge') cprint(u'Arrêt du contrôle %s des membres actifs' % explicite, 'rouge')
break break
def candidats(): def candidats():
@ -74,10 +74,10 @@ def candidats():
def lister(): def lister():
""" """
Afficher les câbleurs fantômes potentiels. Afficher les câbleurs fantômes potentiels.
""" """
todo_list = candidats() todo_list = candidats()
print "Liste des câbleur dont la cotisation n'est pas à jour." print "Liste des câbleur dont la cotisation n'est pas à jour."
print print
for adh in todo_list: for adh in todo_list:
print adh.prenom() + " " + adh.nom() print adh.prenom() + " " + adh.nom()
@ -86,7 +86,7 @@ def lister():
def controle_interactif(): def controle_interactif():
""" """
Procédure interactive de radiations des câbleurs fantômes. Procédure interactive de radiations des câbleurs fantômes.
""" """
todo_list = candidats() todo_list = candidats()
@ -94,7 +94,7 @@ def controle_interactif():
_controle_interactif_adherents(todo_list) _controle_interactif_adherents(todo_list)
def __usage(message=None): def __usage(message=None):
""" Comment ça marche ? """ """ Comment ça marche ? """
cprint(__doc__ % { 'prog': sys.argv[0] }) cprint(__doc__ % { 'prog': sys.argv[0] })
if message: if message:

View file

@ -18,11 +18,11 @@ except:
pass pass
if not encoding: if not encoding:
encoding = sys.stdin.encoding or "ISO-8859-15" encoding = sys.stdin.encoding or 'UTF-8'
# Si aucune locale n'est définie, on se met en ISO-8859-15 # Si aucune locale n'est définie, on se met en...
if encoding == "ANSI_X3.4-1968": if encoding == "ANSI_X3.4-1968":
encoding = "ISO-8859-15" encoding = 'UTF-8'
if 'TERM' in os.environ and os.environ['TERM'] != 'unknown': if 'TERM' in os.environ and os.environ['TERM'] != 'unknown':
el = subprocess.Popen('tput cr ; tput el', shell=True, stdout=subprocess.PIPE).stdout.read() el = subprocess.Popen('tput cr ; tput el', shell=True, stdout=subprocess.PIPE).stdout.read()
@ -115,7 +115,7 @@ def to_unicode(txt, enc=encoding):
return txt.decode("UTF-8") return txt.decode("UTF-8")
except: except:
# Sinon c'est surement de l'iso # Sinon c'est surement de l'iso
return txt.decode("ISO8859-15") return txt.decode("UTF-8")
def to_encoding(txt, enc=encoding): def to_encoding(txt, enc=encoding):
return to_unicode(txt).encode(enc, 'ignore') return to_unicode(txt).encode(enc, 'ignore')

View file

@ -6,7 +6,7 @@
#: Envoyé à la ML disconnect@ en cas de déconnexion pour p2p #: Envoyé à la ML disconnect@ en cas de déconnexion pour p2p
avertissement = u"""From: %(From)s avertissement = u"""From: %(From)s
To: %(To)s To: %(To)s
Subject: =?iso-8859-1?Q?D=E9tection?= de p2p sur la machine %(hostname)s Subject: =?utf-8?q?D=C3=A9tection?= de p2p sur la machine %(hostname)s
Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8"
La machine %(hostname)s a été déconnectée pendant 24h pour La machine %(hostname)s a été déconnectée pendant 24h pour
@ -20,7 +20,7 @@ Message créé par deconnexion.py"""
#: Envoyé à l'adhérent en cas de déconnexion pour p2p #: Envoyé à l'adhérent en cas de déconnexion pour p2p
deconnexion = u"""From: %(From)s deconnexion = u"""From: %(From)s
To: %(To)s To: %(To)s
Subject: Avis de =?iso-8859-15?Q?D=E9connexion?= Subject: Avis de =?utf-8?q?D=C3=A9connexion?=
Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8"
Bonjour, Bonjour,
@ -81,7 +81,7 @@ Disconnect Team"""
#: Envoyé à la ML disconnect@ en cas de déconnexion pour p2p plusieurs fois #: Envoyé à la ML disconnect@ en cas de déconnexion pour p2p plusieurs fois
message_disconnect_multi = u"""From: %(from)s message_disconnect_multi = u"""From: %(from)s
To: %(to)s To: %(to)s
Subject: %(proprio)s a =?iso-8859-15?Q?=E9t=E9=20d=E9connect=E9?= %(nbdeco)d fois pour p2p en un an ! Subject: %(proprio)s a =?utf-8?q?=C3=A9t=C3=A9_d=C3=A9connect=C3=A9?= %(nbdeco)d fois pour p2p en un an !
Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8"
L'adhérent %(proprio)s a été déconnecté %(nbdeco)d fois pour p2p en un an ! L'adhérent %(proprio)s a été déconnecté %(nbdeco)d fois pour p2p en un an !

View file

@ -124,7 +124,7 @@ Message créé par deconnexion.py"""
#: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard #: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard
message_disconnect_hard = u"""From: %(from)s message_disconnect_hard = u"""From: %(from)s
To: %(to)s To: %(to)s
Subject: %(proprio)s a =?iso-8859-1?Q?=E9t=E9=20brid=E9?= Subject: %(proprio)s a =?utf-8?q?=C3=A9t=C3=A9_brid=C3=A9?=
Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8"
%(proprio)s (%(id)s) a été limité en débit montant du fait d'un %(proprio)s (%(id)s) a été limité en débit montant du fait d'un
@ -141,7 +141,7 @@ Message créé par deconnexion.py"""
#: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard plusieurs fois #: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard plusieurs fois
message_disconnect_multi = u"""From: %(from)s message_disconnect_multi = u"""From: %(from)s
To: %(to)s To: %(to)s
Subject: %(proprio)s a =?iso-8859-1?Q?=E9t=E9=20brid=E9?= Subject: %(proprio)s a =?utf-8?q?=C3=A9t=C3=A9_brid=C3=A9?=
%(nbdeco)d fois pour upload en un mois ! %(nbdeco)d fois pour upload en un mois !
Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8"

View file

@ -14,7 +14,7 @@ format_sender et send_email adaptés depuis /usr/scripts/impression/crans_backen
import re import re
def format_sender(sender, header_charset='ISO-8859-15'): def format_sender(sender, header_charset='utf-8'):
""" """
Check and format sender for header. Check and format sender for header.
""" """
@ -42,8 +42,8 @@ def send_email(sender, recipient, subject, body, server='localhost', cc=None, de
Only the real name part of sender and recipient addresses may contain Only the real name part of sender and recipient addresses may contain
non-ASCII characters. The email will be properly MIME encoded. non-ASCII characters. The email will be properly MIME encoded.
The charset of the email will be the first one out of US-ASCII, ISO-8859-15 The charset of the email will be the first one out of US-ASCII or UTF-8
and UTF-8 that can represent all the characters occurring in the email. that can represent all the characters occurring in the email.
Argument server maybe a string, indicating the name of the SMTP server, or Argument server maybe a string, indicating the name of the SMTP server, or
directly an instance of smtplib.SMTP. directly an instance of smtplib.SMTP.
@ -57,10 +57,10 @@ def send_email(sender, recipient, subject, body, server='localhost', cc=None, de
# Header class is smart enough to try US-ASCII, then the charset we # Header class is smart enough to try US-ASCII, then the charset we
# provide, then fall back to UTF-8. # provide, then fall back to UTF-8.
header_charset = 'ISO-8859-15' header_charset = 'UTF-8'
# We must choose the body charset manually # We must choose the body charset manually
for body_charset in 'US-ASCII', 'ISO-8859-15', 'UTF-8': for body_charset in 'US-ASCII', 'UTF-8':
try: try:
body.encode(body_charset) body.encode(body_charset)
except UnicodeError: except UnicodeError:

30
gestion/gen_confs/__init__.py Executable file → Normal file
View file

@ -1,9 +1,9 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" Package pour la génération des fichiers de conf """ Package pour la génération des fichiers de conf
Copyright (C) Frédéric Pauget Copyright (C) Frédéric Pauget
Licence : GPLv2 Licence : GPLv2
""" """
@ -18,11 +18,11 @@ import config
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
class gen_config : class gen_config :
""" Base pour toutes les classes de génération de fichiers de conf """ """ Base pour toutes les classes de génération de fichiers de conf """
base = None base = None
debug = 0 debug = 0
_locked = 0 _locked = 0
__restore={} # pour restorer la config d'origine en cas d'erreur de génération __restore={} # pour restorer la config d'origine en cas d'erreur de génération
def lockname(self): def lockname(self):
"""Nom du lock""" """Nom du lock"""
@ -39,7 +39,7 @@ class gen_config :
if self._locked : remove_lock(self.lockname()) if self._locked : remove_lock(self.lockname())
def __del__(self) : def __del__(self) :
# Au cas où... # Au cas où...
self.unlock() self.unlock()
def _restore(self) : def _restore(self) :
@ -54,12 +54,12 @@ class gen_config :
os.system('cp -f %s %s' % ( f.name, nom ) ) os.system('cp -f %s %s' % ( f.name, nom ) )
def _open_conf(self,nom,comment=None) : def _open_conf(self,nom,comment=None) :
""" Créé un fichier """ Créé un fichier
si comment est fourni, insère une entète qui utilisera le caractère si comment est fourni, insère une entète qui utilisera le caractère
de commentaire fourni de commentaire fourni
copie l'ancien fichier dans un fichier temporaire pour permettre copie l'ancien fichier dans un fichier temporaire pour permettre
la restauration en cas d'échec de la configuration la restauration en cas d'échec de la configuration
Retourne le descripteur du fichier """ Retourne le descripteur du fichier """
@ -89,15 +89,15 @@ class gen_config :
return fd return fd
def gen_conf(self) : def gen_conf(self) :
""" Génération des fichiers de conf, retourne False si erreur """ """ Génération des fichiers de conf, retourne False si erreur """
self.lock() self.lock()
self.anim = anim('\tgénération fichiers') self.anim = anim('\tgénération fichiers')
try : try :
warn = self._gen() warn = self._gen()
if warn : if warn :
self.anim.reinit() self.anim.reinit()
print WARNING print WARNING
if self.debug : sys.stderr.write(warn.encode("ISO-8859-15")) if self.debug : sys.stderr.write(warn.encode("UTF-8"))
else : else :
self.anim.reinit() self.anim.reinit()
print OK print OK
@ -110,7 +110,7 @@ class gen_config :
return False return False
def restart(self) : def restart(self) :
""" Redémarrage du service concerné """ """ Redémarrage du service concerné """
if not self.restart_cmd : return if not self.restart_cmd : return
self.lock() self.lock()
self.anim = anim('\trestart') self.anim = anim('\trestart')
@ -127,8 +127,8 @@ class gen_config :
self.unlock() self.unlock()
def reconfigure(self) : def reconfigure(self) :
""" Génère les fichiers puis redémarre le service """ Génère les fichiers puis redémarre le service
si la génération c'est bien passée """ si la génération c'est bien passée """
cprint(u'Reconfiguration %s :' % self.__str__(), 'gras') cprint(u'Reconfiguration %s :' % self.__str__(), 'gras')
if self.gen_conf() : if self.gen_conf() :
return self.restart() return self.restart()

View file

@ -1,7 +1,7 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
# Copyright (C) Frédéric Pauget # Copyright (C) Frédéric Pauget
# Licence : GPLv2 # Licence : GPLv2
import smtplib, sys, commands, shutil, os, traceback import smtplib, sys, commands, shutil, os, traceback
@ -18,7 +18,7 @@ try:
from Mailman.UserDesc import UserDesc from Mailman.UserDesc import UserDesc
from Mailman.Errors import MMAlreadyAMember from Mailman.Errors import MMAlreadyAMember
except: except:
# Machine sans mailman, les ML ne seront pas reconfigurées # Machine sans mailman, les ML ne seront pas reconfigurées
pass pass
@ -101,7 +101,7 @@ class home:
self.args = args self.args = args
def reconfigure(self): def reconfigure(self):
cprint(u'Création home', 'gras') cprint(u'Création home', 'gras')
for args in self.args: for args in self.args:
anim('\t' + args) anim('\t' + args)
try: try:
@ -116,11 +116,11 @@ class home:
os.mkdir(home, 0755) os.mkdir(home, 0755)
os.chown(home, int(uid), config.gid) os.chown(home, int(uid), config.gid)
elif os.path.isdir(home): elif os.path.isdir(home):
# Il y un répertoire existant # Il y un répertoire existant
# Bon UID ? # Bon UID ?
stat = os.stat(home) stat = os.stat(home)
if stat[4] != int(uid) or stat[5] != config.gid: if stat[4] != int(uid) or stat[5] != config.gid:
# Le home n'est pas pas à la bonne personne # Le home n'est pas pas à la bonne personne
raise OSError('home existant') raise OSError('home existant')
### Quota ### Quota
@ -226,7 +226,7 @@ class ML_ens:
try: try:
mlist.ApprovedAddMember(UserDesc(mail)) mlist.ApprovedAddMember(UserDesc(mail))
except MMAlreadyAMember: except MMAlreadyAMember:
cprint(u"DÉJÀ INSCRIT", "jaune") cprint(u"DÉJÀ INSCRIT", "jaune")
except: except:
print ERREUR print ERREUR
if self.debug: if self.debug:

View file

@ -1,9 +1,9 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" Génération de la configuration pour bind9 """ Génération de la configuration pour bind9
Copyright (C) Frédéric Pauget Copyright (C) Frédéric Pauget
Licence : GPLv2 Licence : GPLv2
""" """
import time, sys, re, hashlib, base64, os import time, sys, re, hashlib, base64, os
@ -56,36 +56,36 @@ def netv6_to_arpa(net):
class dns(gen_config) : class dns(gen_config) :
""" """
Génération des fichiers de configuration de bind9 : Génération des fichiers de configuration de bind9 :
* fichier DNS_CONF qui contient les définitions de zone conformément * fichier DNS_CONF qui contient les définitions de zone conformément
à zone_template. Ce fichier doit être inclus à partir de la config statique à zone_template. Ce fichier doit être inclus à partir de la config statique
de bind de bind
* les fichiers de zones, ce sont eux qui contiennent les données du * les fichiers de zones, ce sont eux qui contiennent les données du
dns, ils ont appellés par le fichier DNS_CONF et sont générés dans DNS_DIR dns, ils ont appellés par le fichier DNS_CONF et sont générés dans DNS_DIR
Leur entète est générée à partir de zone_entete. Leur entète est générée à partir de zone_entete.
Les fichiers générés placent bind comme autoritaire sur les noms de Les fichiers générés placent bind comme autoritaire sur les noms de
zones_direct et les adresses de zones_reverse. Les données proviennent de zones_direct et les adresses de zones_reverse. Les données proviennent de
la base LDAP la base LDAP
""" """
######################################PARTIE DE CONFIGURATION ######################################PARTIE DE CONFIGURATION
### Fichiers à écrire ### Fichiers à écrire
# Répertoire d'écriture des fichiers de zone # Répertoire d'écriture des fichiers de zone
DNS_DIR = '/etc/bind/generated/' # Avec un / à la fin DNS_DIR = '/etc/bind/generated/' # Avec un / à la fin
DNSSEC_DIR = '/etc/bind/signed/' # Avec un / à la fin DNSSEC_DIR = '/etc/bind/signed/' # Avec un / à la fin
# Fichier de définition des zones pour le maître # Fichier de définition des zones pour le maître
DNS_CONF = DNS_DIR + 'zones_crans' DNS_CONF = DNS_DIR + 'zones_crans'
# Fichier de définition des zones pour les esclaves géré par BCfg2 # Fichier de définition des zones pour les esclaves géré par BCfg2
DNS_CONF_BCFG2 = "/var/lib/bcfg2/Cfg/etc/bind/generated/zones_crans/zones_crans" DNS_CONF_BCFG2 = "/var/lib/bcfg2/Cfg/etc/bind/generated/zones_crans/zones_crans"
### Sur quelles zones on a autorité ? ### Sur quelles zones on a autorité ?
## En cas de modification de ces zones penser à regéner le fichier de ## En cas de modification de ces zones penser à regéner le fichier de
## zone des esclaves (sur le serveur principal de bcfg2 : python /usr/scripts/gestion/gen_confs/bind.py puis lancer bcfg2 sur les miroirs) ## zone des esclaves (sur le serveur principal de bcfg2 : python /usr/scripts/gestion/gen_confs/bind.py puis lancer bcfg2 sur les miroirs)
# Résolution directe # Résolution directe
zones_direct = config.dns.zones_direct zones_direct = config.dns.zones_direct
# Zones signée par opendnssec sur le serveur maitre # Zones signée par opendnssec sur le serveur maitre
zones_dnssec = config.dns.zones_dnssec zones_dnssec = config.dns.zones_dnssec
# Zones alias pour les enregistrement A AAAA CNAME TXT et SSHFP # Zones alias pour les enregistrement A AAAA CNAME TXT et SSHFP
zone_alias = config.dns.zone_alias zone_alias = config.dns.zone_alias
@ -97,7 +97,7 @@ la base LDAP
'adm.crans.org': 'adm.v6.crans.org', 'adm.crans.org': 'adm.v6.crans.org',
'ferme.crans.org': 'ferme.v6.crans.org', 'ferme.crans.org': 'ferme.v6.crans.org',
} }
# Résolution inverse # Résolution inverse
zones_reverse = config.dns.zones_reverse zones_reverse = config.dns.zones_reverse
zones_v6_to_net = { zones_v6_to_net = {
'crans.eu': config.prefix["fil"][0], 'crans.eu': config.prefix["fil"][0],
@ -105,26 +105,26 @@ la base LDAP
'wifi.crans.org': config.prefix["wifi"][0], 'wifi.crans.org': config.prefix["wifi"][0],
'adm.crans.org': config.prefix["adm"][0], 'adm.crans.org': config.prefix["adm"][0],
'ferme.crans.org': config.prefix["fil"][0], 'ferme.crans.org': config.prefix["fil"][0],
# Hack pour générer un fichier de zone vide # Hack pour générer un fichier de zone vide
'##HACK##': config.prefix["subnet"][0], '##HACK##': config.prefix["subnet"][0],
} }
### Liste DNS ### Liste DNS
# Le premier doit être le maitre # Le premier doit être le maitre
DNSs = ['sable.crans.org', 'freebox.crans.org', 'ovh.crans.org'] DNSs = ['sable.crans.org', 'freebox.crans.org', 'ovh.crans.org']
DNSs_private = [] DNSs_private = []
ip_master_DNS = config.dns.master ip_master_DNS = config.dns.master
zone_multicast = 'tv.crans.org' zone_multicast = 'tv.crans.org'
### Liste des délégations de zone ### Liste des délégations de zone
# Pour les demandes de ces zones, le DNS dira d'aller voir les serveurs listés ici # Pour les demandes de ces zones, le DNS dira d'aller voir les serveurs listés ici
# Pour les noms des serveurs on met l'IP sans point ou le nom avec un point # Pour les noms des serveurs on met l'IP sans point ou le nom avec un point
DELEG = { DELEG = {
zone_multicast : [ 'sable.crans.org.' , 'mdr.crans.org.', 'freebox.crans.org.', 'ovh.crans.org.'] , zone_multicast : [ 'sable.crans.org.' , 'mdr.crans.org.', 'freebox.crans.org.', 'ovh.crans.org.'] ,
} }
### Serveurs de mail ### Serveurs de mail
# format : [ priorité serveur , .... ] # format : [ priorité serveur , .... ]
MXs = ['10 redisdead.crans.org', '20 ovh.crans.org', '20 freebox.crans.org'] MXs = ['10 redisdead.crans.org', '20 ovh.crans.org', '20 freebox.crans.org']
SRVs = [ SRVs = [
'_jabber._tcp.crans.org. 86400 IN SRV 5 0 5269 xmpp.crans.org.', '_jabber._tcp.crans.org. 86400 IN SRV 5 0 5269 xmpp.crans.org.',
@ -135,7 +135,7 @@ la base LDAP
'_sips._tcp.crans.org. 86400 IN SRV 5 0 5061 asterisk.crans.org.', '_sips._tcp.crans.org. 86400 IN SRV 5 0 5061 asterisk.crans.org.',
] ]
# DS à publier dans zone parentes : { parent : [ zone. TTL IN DS key_id algo_id 1 hash ] } # DS à publier dans zone parentes : { parent : [ zone. TTL IN DS key_id algo_id 1 hash ] }
# ex : { 'crans.eu' : ['wifi.crans.eu. 86400 IN DS 33131 8 1 3B573B0E2712D8A8B1B0C3'] } # ex : { 'crans.eu' : ['wifi.crans.eu. 86400 IN DS 33131 8 1 3B573B0E2712D8A8B1B0C3'] }
# /!\ Il faut faire attention au rollback des keys, il faudrait faire quelque chose d'automatique avec opendnssec # /!\ Il faut faire attention au rollback des keys, il faudrait faire quelque chose d'automatique avec opendnssec
DS = { DS = {
@ -161,7 +161,7 @@ la base LDAP
} }
### Entète des fichiers de zone ### Entète des fichiers de zone
zone_entete=""" zone_entete="""
$ORIGIN %(zone)s. $ORIGIN %(zone)s.
$TTL 3600 $TTL 3600
@ -174,14 +174,14 @@ $TTL 3600
) )
""" """
# Syntaxe utilisée dans le fichier DNS_CONF pour définir une zone sur le maître # Syntaxe utilisée dans le fichier DNS_CONF pour définir une zone sur le maître
zone_template=""" zone_template="""
zone "%(NOM_zone)s" { zone "%(NOM_zone)s" {
type master; type master;
file "%(FICHIER_zone)s"; file "%(FICHIER_zone)s";
}; };
""" """
# Syntaxe utilisée dans le fichier DNS_CONF_BCFG2 pour définir une zone sur un esclave # Syntaxe utilisée dans le fichier DNS_CONF_BCFG2 pour définir une zone sur un esclave
zone_template_slave=""" zone_template_slave="""
zone "%(NOM_zone)s" { zone "%(NOM_zone)s" {
type slave; type slave;
@ -190,10 +190,10 @@ zone "%(NOM_zone)s" {
}; };
""" """
### Verbosité ### Verbosité
# Si =2, ralera (chaine warnings) si machines hors zone trouvée # Si =2, ralera (chaine warnings) si machines hors zone trouvée
# Si =1, comme ci-dessus, mais ne ralera pas pour freebox # Si =1, comme ci-dessus, mais ne ralera pas pour freebox
# Si =0, ralera seulement contre les machines ne pouvant être classées # Si =0, ralera seulement contre les machines ne pouvant être classées
verbose = 1 verbose = 1
hostname = short_name(gethostname()) hostname = short_name(gethostname())
@ -208,8 +208,8 @@ zone "%(NOM_zone)s" {
return "DNS" return "DNS"
def reverse(self, net, ip): def reverse(self, net, ip):
"""Renvoie la zone DNS inverse correspondant au réseau et à """Renvoie la zone DNS inverse correspondant au réseau et à
l'adresse donnés, ainsi que le nombre d'éléments de l'ip a l'adresse donnés, ainsi que le nombre d'éléments de l'ip a
mettre dans le fichier de zone.""" mettre dans le fichier de zone."""
n = netaddr.IPNetwork(net) n = netaddr.IPNetwork(net)
a = netaddr.IPAddress(ip) a = netaddr.IPAddress(ip)
@ -228,7 +228,7 @@ zone "%(NOM_zone)s" {
zone_reverse=netv4_to_arpa(config.NETs['multicast'][0])[0] zone_reverse=netv4_to_arpa(config.NETs['multicast'][0])[0]
sap=open('/tmp/chaines_recup_sap.txt').readlines() sap=open('/tmp/chaines_recup_sap.txt').readlines()
DNS='; DNS de la zone par ordre de priorité\n' DNS='; DNS de la zone par ordre de priorité\n'
for d in self.DELEG[self.zone_multicast] : for d in self.DELEG[self.zone_multicast] :
DNS += '@\tIN\tNS %s\n' % d DNS += '@\tIN\tNS %s\n' % d
DNS += '\n' DNS += '\n'
@ -238,9 +238,9 @@ zone "%(NOM_zone)s" {
lignes_d +='@\tIN\tA\t%s\n' % '138.231.136.243' lignes_d +='@\tIN\tA\t%s\n' % '138.231.136.243'
for line in sap: for line in sap:
[nom,ip]=line.split(':') [nom,ip]=line.split(':')
nom=re.sub('TNT([0-9]*) ','',nom) # on enlève les TNT## des noms nom=re.sub('TNT([0-9]*) ','',nom) # on enlève les TNT## des noms
nom=re.sub(' +([^ ])','-\g<1>',nom) # on remplaces les espaces intérieur par un tiret nom=re.sub(' +([^ ])','-\g<1>',nom) # on remplaces les espaces intérieur par un tiret
nom=re.sub('[ .():,"\'+<>]','',nom) # on enlève tous les caractères illégaux nom=re.sub('[ .():,"\'+<>]','',nom) # on enlève tous les caractères illégaux
nom=nom.lower() nom=nom.lower()
try: try:
[ip1,ip2,ip3,ip4]=ip.strip().split('.') [ip1,ip2,ip3,ip4]=ip.strip().split('.')
@ -248,7 +248,7 @@ zone "%(NOM_zone)s" {
lignes_d +='%s\tIN\tA\t%s' % (nom,ip) lignes_d +='%s\tIN\tA\t%s' % (nom,ip)
except: except:
pass pass
# Écriture de la zone directe # Écriture de la zone directe
file = self.DNS_DIR + 'db.' + self.zone_multicast file = self.DNS_DIR + 'db.' + self.zone_multicast
fd = self._open_conf(file,';') fd = self._open_conf(file,';')
fd.write(self.zone_entete % \ fd.write(self.zone_entete % \
@ -258,7 +258,7 @@ zone "%(NOM_zone)s" {
fd.write(lignes_d) fd.write(lignes_d)
fd.close() fd.close()
# Écriture du reverse # Écriture du reverse
file = self.DNS_DIR + 'db.' + zone_reverse file = self.DNS_DIR + 'db.' + zone_reverse
fd = self._open_conf(file,';') fd = self._open_conf(file,';')
fd.write(self.zone_entete % \ fd.write(self.zone_entete % \
@ -270,7 +270,7 @@ zone "%(NOM_zone)s" {
def gen_slave(self) : def gen_slave(self) :
""" Génération du fichier de config de zone pour les esclaves """ """ Génération du fichier de config de zone pour les esclaves """
zones = self.zones_direct zones = self.zones_direct
zones.extend(self.zones_v4_to_v6.values()) zones.extend(self.zones_v4_to_v6.values())
@ -297,13 +297,13 @@ zone "%(NOM_zone)s" {
fd.close() fd.close()
def _gen(self) : def _gen(self) :
### Génération du numéro de série ### Génération du numéro de série
# Le + 1000.... s'explique pas l'idée précédente et peu pratique d'avoir # Le + 1000.... s'explique pas l'idée précédente et peu pratique d'avoir
# le numéro de série du type AAAAMMJJNN (année, mois, jour, incrément par jour) # le numéro de série du type AAAAMMJJNN (année, mois, jour, incrément par jour)
serial = time.time() + 1000000000 serial = time.time() + 1000000000
### DNS ### DNS
DNS='; DNS de la zone par ordre de priorité\n' DNS='; DNS de la zone par ordre de priorité\n'
for d in self.DNSs : for d in self.DNSs :
DNS += '@\tIN\tNS %s.\n' % d DNS += '@\tIN\tNS %s.\n' % d
DNS += '\n' DNS += '\n'
@ -311,7 +311,7 @@ zone "%(NOM_zone)s" {
### Serveurs de mail ### Serveurs de mail
MX='; Serveurs de mails\n' MX='; Serveurs de mails\n'
for m in self.MXs : for m in self.MXs :
MX += '%(zone)s.\t' # Sera remplacé par le nom de zone plus tard MX += '%(zone)s.\t' # Sera remplacé par le nom de zone plus tard
MX += 'IN\tMX\t%s.\n' % m MX += 'IN\tMX\t%s.\n' % m
MX += '\n' MX += '\n'
@ -345,12 +345,12 @@ zone "%(NOM_zone)s" {
self.anim.iter=len(self.machines) self.anim.iter=len(self.machines)
for machine in self.machines : for machine in self.machines :
self.anim.cycle() self.anim.cycle()
# Calculs préliminaires # Calculs préliminaires
try : try :
nom , zone = machine.nom().split('.',1) nom , zone = machine.nom().split('.',1)
zone = zone.encode('iso-8859-1') zone = zone.encode('utf-8')
except : except :
warnings += u'Machine ignorée (mid=%s) : format nom incorrect (%s)\n' % ( machine.id().encode('iso-8859-1'), machine.nom().encode('iso-8859-1') ) warnings += u'Machine ignorée (mid=%s) : format nom incorrect (%s)\n' % ( machine.id().encode('utf-8'), machine.nom().encode('utf-8') )
continue continue
# Le direct # Le direct
@ -359,7 +359,7 @@ zone "%(NOM_zone)s" {
# Si la machine est une borne wifi, on ajoute la position # Si la machine est une borne wifi, on ajoute la position
if isinstance(machine,ldap_crans.BorneWifi) and machine.position(): if isinstance(machine,ldap_crans.BorneWifi) and machine.position():
ligne +="%s\tIN\tTXT\t\"LOC %s,%s \"\n" % (nom,machine.position()[0],machine.position()[1]) ligne +="%s\tIN\tTXT\t\"LOC %s,%s \"\n" % (nom,machine.position()[0],machine.position()[1])
# Si la machine à des clefs ssh, on ajoute les champs SSFP correspondant # Si la machine à des clefs ssh, on ajoute les champs SSFP correspondant
for sshkey in machine.sshFingerprint(): for sshkey in machine.sshFingerprint():
try: try:
[algo_txt,key]=sshkey.split()[:2] [algo_txt,key]=sshkey.split()[:2]
@ -378,7 +378,7 @@ zone "%(NOM_zone)s" {
for alias in self.zone_alias[zone]: for alias in self.zone_alias[zone]:
direct[alias] = direct.get(alias, "") + ligne direct[alias] = direct.get(alias, "") + ligne
elif self.verbose and machine.nom() != "ftp.federez.net": elif self.verbose and machine.nom() != "ftp.federez.net":
warnings += u'Résolution directe ignorée (mid=%s) : zone non autoritaire (%s)\n' % ( machine.id().encode('iso-8859-1'), zone.encode('iso-8859-1') ) warnings += u'Résolution directe ignorée (mid=%s) : zone non autoritaire (%s)\n' % ( machine.id().encode('utf-8'), zone.encode('utf-8') )
# IPv6 # IPv6
if zone in self.zones_v4_to_v6: if zone in self.zones_v4_to_v6:
@ -406,23 +406,23 @@ zone "%(NOM_zone)s" {
# Le direct avec alias # Le direct avec alias
for alias in machine.alias() : for alias in machine.alias() :
alias = alias.encode('iso-8859-1') alias = alias.encode('utf-8')
# Cas particulier : nom de l'alias = nom de la zone # Cas particulier : nom de l'alias = nom de la zone
if alias in self.zones_direct : if alias in self.zones_direct :
ligne = "@\tIN\tA\t%s\n" % machine.ip() ligne = "@\tIN\tA\t%s\n" % machine.ip()
ligne = ligne.encode('iso-8859-1') ligne = ligne.encode('utf-8')
direct[alias] = direct.get(alias, "") + ligne direct[alias] = direct.get(alias, "") + ligne
if alias in self.zone_alias: if alias in self.zone_alias:
for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne
if machine.dnsIpv6(): if machine.dnsIpv6():
ligne = "@\tIN\tAAAA\t%s\n" % machine.ipv6() ligne = "@\tIN\tAAAA\t%s\n" % machine.ipv6()
ligne = ligne.encode('iso-8859-1') ligne = ligne.encode('utf-8')
direct[alias]= direct.get(alias, "") + ligne direct[alias]= direct.get(alias, "") + ligne
if alias in self.zone_alias: if alias in self.zone_alias:
for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne
if alias in self.zones_v4_to_v6: if alias in self.zones_v4_to_v6:
ligne = "@\tIN\tAAAA\t%s\n" % machine.ipv6() ligne = "@\tIN\tAAAA\t%s\n" % machine.ipv6()
ligne = ligne.encode('iso-8859-1') ligne = ligne.encode('utf-8')
zone6 = self.zones_v4_to_v6[alias] zone6 = self.zones_v4_to_v6[alias]
direct[zone6] = direct.get(zone6, '') + ligne direct[zone6] = direct.get(zone6, '') + ligne
if alias in self.zone_alias: if alias in self.zone_alias:
@ -445,9 +445,9 @@ zone "%(NOM_zone)s" {
ok = 1 ok = 1
break break
if not ok: if not ok:
warnings += u'Alias ignoré (mid=%s) : %s\n' % ( machine.id().encode('iso-8859-1'), alias.encode('iso-8859-1') ) warnings += u'Alias ignoré (mid=%s) : %s\n' % ( machine.id().encode('utf-8'), alias.encode('utf-8') )
continue continue
zone = zone.encode('iso-8859-1') zone = zone.encode('utf-8')
ligne = "%s\tIN\tCNAME\t%s.\n" % ( nom, machine.nom() ) ligne = "%s\tIN\tCNAME\t%s.\n" % ( nom, machine.nom() )
direct[zone] = direct.get(zone, '') + ligne direct[zone] = direct.get(zone, '') + ligne
if zone in self.zones_v4_to_v6: if zone in self.zones_v4_to_v6:
@ -468,40 +468,40 @@ zone "%(NOM_zone)s" {
base_ip = ip.split('.') base_ip = ip.split('.')
base_ip.reverse() base_ip.reverse()
zone, length = self.reverse(net, ip) zone, length = self.reverse(net, ip)
zone = zone.encode('iso-8859-1') zone = zone.encode('utf-8')
ligne = '%s\tIN\tPTR\t%s.\n' % ('.'.join(base_ip[:length]), machine.nom()) ligne = '%s\tIN\tPTR\t%s.\n' % ('.'.join(base_ip[:length]), machine.nom())
try : reverse[zone] += ligne try : reverse[zone] += ligne
except : reverse[zone] = ligne except : reverse[zone] = ligne
elif self.verbose >= 2 or machine.nom() not in ('freebox.crans.org', 'ovh.crans.org', 'kokarde.crans.org'): elif self.verbose >= 2 or machine.nom() not in ('freebox.crans.org', 'ovh.crans.org', 'kokarde.crans.org'):
warnings += u'Résolution inverse ignorée (mid=%s) : ip sur zone non autoritaire (%s)\n' % ( machine.id().encode('iso-8859-1'), machine.ip().encode('iso-8859-1') ) warnings += u'Résolution inverse ignorée (mid=%s) : ip sur zone non autoritaire (%s)\n' % ( machine.id().encode('utf-8'), machine.ip().encode('utf-8') )
### Ajouts pour les fichiers de résolution directs ### Ajouts pour les fichiers de résolution directs
for zone in direct.keys() : for zone in direct.keys() :
# MXs # MXs
direct[zone] = MX % { 'zone' : zone } + direct[zone] direct[zone] = MX % { 'zone' : zone } + direct[zone]
### XXX: création de la zone inverse pour le /48 IPv6 complet du Cr@ns ### XXX: création de la zone inverse pour le /48 IPv6 complet du Cr@ns
full_net_v6 = self.zones_v6_to_net["##HACK##"] full_net_v6 = self.zones_v6_to_net["##HACK##"]
zone_rev, length = self.reverse(full_net_v6, netaddr.IPNetwork(full_net_v6).first) zone_rev, length = self.reverse(full_net_v6, netaddr.IPNetwork(full_net_v6).first)
reverse[zone_rev] = reverse.get(zone_rev, "") reverse[zone_rev] = reverse.get(zone_rev, "")
### Ajout des délégations de zones ### Ajout des délégations de zones
for deleg in self.DELEG.keys(): for deleg in self.DELEG.keys():
nom, zone = deleg.split('.',1) nom, zone = deleg.split('.',1)
if not zone in direct.keys(): if not zone in direct.keys():
warnings += u'Délégation ignorée %s : on ne génère pas la zone parent\n' % deleg warnings += u'Délégation ignorée %s : on ne génère pas la zone parent\n' % deleg
continue continue
for serv in self.DELEG[deleg]: for serv in self.DELEG[deleg]:
direct[zone] = direct[zone] + "%s\tIN\tNS\t%s\n" % ( nom, serv ) direct[zone] = direct[zone] + "%s\tIN\tNS\t%s\n" % ( nom, serv )
### Ajout d'eventuel champs DS pour les délégation dnssec ### Ajout d'eventuel champs DS pour les délégation dnssec
for zone,ds in self.DS.items(): for zone,ds in self.DS.items():
for s in ds: for s in ds:
direct[zone] += s + '\n' direct[zone] += s + '\n'
direct[zone] += '\n' direct[zone] += '\n'
### Ecriture des fichiers de zone et préparation du fichier de définition ### Ecriture des fichiers de zone et préparation du fichier de définition
f = '' f = ''
for zone, lignes in direct.items() + reverse.items() : for zone, lignes in direct.items() + reverse.items() :
if zone in self.zones_dnssec: if zone in self.zones_dnssec:
@ -523,7 +523,7 @@ zone "%(NOM_zone)s" {
else: else:
f += self.zone_template % { 'NOM_zone' : zone, 'FICHIER_zone' : path } f += self.zone_template % { 'NOM_zone' : zone, 'FICHIER_zone' : path }
### Ecriture fichier de définition ### Ecriture fichier de définition
fd = self._open_conf(self.DNS_CONF,'//') fd = self._open_conf(self.DNS_CONF,'//')
fd.write(f) fd.write(f)
fd.close() fd.close()
@ -535,13 +535,13 @@ if __name__ == '__main__' :
from config import bcfg2_main from config import bcfg2_main
hostname = short_name(gethostname()) hostname = short_name(gethostname())
if hostname == short_name(bcfg2_main): if hostname == short_name(bcfg2_main):
print "Reconfiguration du fichier de BCfg2 pour configurer le bind d'un serveur en esclave (pensez à lancer bcfg2 sur les esclaves)." print "Reconfiguration du fichier de BCfg2 pour configurer le bind d'un serveur en esclave (pensez à lancer bcfg2 sur les esclaves)."
c = dns() c = dns()
c.gen_slave() c.gen_slave()
if hostname == short_name(dns.DNSs[0]): if hostname == short_name(dns.DNSs[0]):
print "Ce serveur est également serveur maitre, mais la reconfiguration du DNS maitre se fait par generate." print "Ce serveur est également serveur maitre, mais la reconfiguration du DNS maitre se fait par generate."
elif hostname == short_name(dns.DELEG['tv.crans.org'][0][0:-1]): elif hostname == short_name(dns.DELEG['tv.crans.org'][0][0:-1]):
print "Serveur ma�tre pour tv.crans.org, génération de la zone" print "Serveur maᅵtre pour tv.crans.org, génération de la zone"
c = dns() c = dns()
c.gen_tv() c.gen_tv()
import subprocess import subprocess
@ -551,10 +551,10 @@ if __name__ == '__main__' :
print ret[0].strip() print ret[0].strip()
print ret[1].strip() print ret[1].strip()
if hostname == short_name(dns.DNSs[0]): if hostname == short_name(dns.DNSs[0]):
print "Ce serveur est également serveur maitre, mais la reconfiguration du DNS maitre se fait par generate." print "Ce serveur est également serveur maitre, mais la reconfiguration du DNS maitre se fait par generate."
elif hostname == short_name(dns.DNSs[0]): elif hostname == short_name(dns.DNSs[0]):
print "Ce serveur est maître ! Utilisez generate." print "Ce serveur est maître ! Utilisez generate."
elif hostname in map(lambda fullhostname : short_name(fullhostname),dns.DNSs[1:]+dns.DNSs_private): elif hostname in map(lambda fullhostname : short_name(fullhostname),dns.DNSs[1:]+dns.DNSs_private):
print "Ce serveur est esclave! Lancez ce script sur %s, puis lancez bcfg2 ici" % bcfg2_main print "Ce serveur est esclave! Lancez ce script sur %s, puis lancez bcfg2 ici" % bcfg2_main
else: else:
print "Ce serveur ne correspond à rien pour la configuration DNS." print "Ce serveur ne correspond à rien pour la configuration DNS."

View file

@ -1,9 +1,9 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" Génération de la configuration pour le dhcp """ Génération de la configuration pour le dhcp
Copyright (C) Frédéric Pauget Copyright (C) Frédéric Pauget
Licence : GPLv2 Licence : GPLv2
""" """
@ -12,22 +12,22 @@ from gen_confs import gen_config
from ldap_crans import hostname from ldap_crans import hostname
class dhcp(gen_config) : class dhcp(gen_config) :
""" Génération du fichier de configuration pour dhcpd (DHCPD_CONF) """ Génération du fichier de configuration pour dhcpd (DHCPD_CONF)
Le fichier comporte une partie par réseau servi, chaque réseau Le fichier comporte une partie par réseau servi, chaque réseau
servi doit être une clef du dictionnaire reseaux, la valeur correspondante servi doit être une clef du dictionnaire reseaux, la valeur correspondante
est une chaine décrivant les options spécifiques à ce réseau. est une chaine décrivant les options spécifiques à ce réseau.
Les options communes sont celles de base_dhcp. Les options communes sont celles de base_dhcp.
Chaque machines possède ensuite une entrée de la forme de host_template Chaque machines possède ensuite une entrée de la forme de host_template
""" """
######################################PARTIE DE CONFIGURATION ######################################PARTIE DE CONFIGURATION
# Fichier à écire # Fichier à écire
if hostname == 'ragnarok' : if hostname == 'ragnarok' :
DHCPD_CONF='/etc/dhcpd.conf' DHCPD_CONF='/etc/dhcpd.conf'
else : else :
DHCPD_CONF = '/etc/dhcp3/dhcpd.conf' DHCPD_CONF = '/etc/dhcp3/dhcpd.conf'
# Hotspot ENS plus utilisé... # Hotspot ENS plus utilisé...
# elif hostname == 'ragnarok' : # elif hostname == 'ragnarok' :
# On rajoute les IP dynamiques # On rajoute les IP dynamiques
# base_conf = """ # base_conf = """
@ -47,7 +47,7 @@ class dhcp(gen_config) :
#""" #"""
elif hostname == 'sable': elif hostname == 'sable':
# Options communes à toutes les réseaux servis # Options communes à toutes les réseaux servis
base_conf=""" base_conf="""
# VLan accueil # VLan accueil
subnet 10.51.0.0 netmask 255.255.0.0 { subnet 10.51.0.0 netmask 255.255.0.0 {
@ -68,7 +68,7 @@ subnet 10.52.0.0 netmask 255.255.0.0 {
else : else :
base_conf = '' base_conf = ''
# Réseaux servis avec leurs options spécifiques # Réseaux servis avec leurs options spécifiques
# if hostname == 'zamok': # if hostname == 'zamok':
# reseaux = { '138.231.136.0/21' : # reseaux = { '138.231.136.0/21' :
#"""option routers 138.231.136.4; #"""option routers 138.231.136.4;
@ -110,7 +110,7 @@ subnet 10.52.0.0 netmask 255.255.0.0 {
option routers 10.42.0.1; option routers 10.42.0.1;
option domain-name-servers 10.42.0.1;""" } option domain-name-servers 10.42.0.1;""" }
# Options communes à toutes les réseaux servis # Options communes à toutes les réseaux servis
base_dhcp=""" base_dhcp="""
subnet %(network)s netmask %(netmask)s { subnet %(network)s netmask %(netmask)s {
default-lease-time 86400; default-lease-time 86400;
@ -153,9 +153,9 @@ subnet %(network)s netmask %(netmask)s {
} }
""" """
### Verbosité ### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée # Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement si réseau vide # Si =0 ralera seulement si réseau vide
verbose = 1 verbose = 1
# if hostname == 'zamok': # if hostname == 'zamok':
@ -195,7 +195,7 @@ subnet %(network)s netmask %(netmask)s {
fd.write(self.base_conf) fd.write(self.base_conf)
for net, options in self.reseaux.items() : for net, options in self.reseaux.items() :
if not hosts.has_key(net) : if not hosts.has_key(net) :
warnings += u'Réseau %s ignoré : aucune machine à servir\n' % net warnings += u'Réseau %s ignoré : aucune machine à servir\n' % net
continue continue
d = param(net) d = param(net)
d['OPTIONS_RESEAU'] = options d['OPTIONS_RESEAU'] = options

View file

@ -1,9 +1,9 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" Génération de la configuration pour le dhcp """ Génération de la configuration pour le dhcp
Copyright (C) Frédéric Pauget Copyright (C) Frédéric Pauget
Licence : GPLv2 Licence : GPLv2
""" """
import os import os
@ -63,15 +63,15 @@ class dydhcp:
conn.close() conn.close()
class dhcp(gen_config) : class dhcp(gen_config) :
""" Génération du fichier de déclaration des hosts. """ Génération du fichier de déclaration des hosts.
Chaque réseau servi doit être une clef du dictionnaire reseaux, Chaque réseau servi doit être une clef du dictionnaire reseaux,
la valeur correspondante est une chaine contenant le nom du fichier la valeur correspondante est une chaine contenant le nom du fichier
associé à ce réseau. associé à ce réseau.
Chaque machine possède ensuite une entrée de la forme de host_template. Chaque machine possède ensuite une entrée de la forme de host_template.
""" """
######################################PARTIE DE CONFIGURATION ######################################PARTIE DE CONFIGURATION
# Fichier à écire # Fichier à écire
if hostname == 'sable': if hostname == 'sable':
restart_cmd = '/etc/init.d/isc-dhcp-server restart' restart_cmd = '/etc/init.d/isc-dhcp-server restart'
reseaux = { '138.231.136.0/21' : '/etc/dhcp3/generated/adherents.liste', reseaux = { '138.231.136.0/21' : '/etc/dhcp3/generated/adherents.liste',
@ -114,9 +114,9 @@ class dhcp(gen_config) :
} }
""" """
### Verbosité ### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée # Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement si réseau vide # Si =0 ralera seulement si réseau vide
verbose = 1 verbose = 1
######################################FIN PARTIE DE CONFIGURATION ######################################FIN PARTIE DE CONFIGURATION
@ -145,7 +145,7 @@ class dhcp(gen_config) :
def _gen(self) : def _gen(self) :
"""Construction de la liste des machines appartenant à un réseau """Construction de la liste des machines appartenant à un réseau
""" """
warnings = '' warnings = ''

View file

@ -1,7 +1,7 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
# Copyright (C) Frédéric Pauget # Copyright (C) Frédéric Pauget
# Licence : GPLv2 # Licence : GPLv2
#"""Ce script permet de lancer la reconfiguration des divers services #"""Ce script permet de lancer la reconfiguration des divers services
@ -9,8 +9,8 @@
#Usage: %(prog)s options #Usage: %(prog)s options
#Les options possibles sont : #Les options possibles sont :
#\t%(options)s #\t%(options)s
#Les options avec = doivent être suivies d'un argument. Plusieurs #Les options avec = doivent être suivies d'un argument. Plusieurs
#arguments peuvent être founis pour une même option, les séparer par & #arguments peuvent être founis pour une même option, les séparer par &
#""" #"""
import sys, signal, os, getopt import sys, signal, os, getopt
@ -68,19 +68,19 @@ class base_reconfigure:
def __init__(self, to_do=None): def __init__(self, to_do=None):
# On vérifie que l'on est root # On vérifie que l'on est root
if os.getuid() != 0: if os.getuid() != 0:
sys.stderr.write("Il faut être root\n") sys.stderr.write("Il faut être root\n")
sys.exit(1) sys.exit(1)
if not to_do: if not to_do:
if debug: if debug:
print 'Lecture des services à redémarrer dans la base LDAP...' print 'Lecture des services à redémarrer dans la base LDAP...'
auto = True auto = True
to_do = {} to_do = {}
# Création de la liste de ce qu'il y a à faire # Création de la liste de ce qu'il y a à faire
for serv in db.services_to_restart(): for serv in db.services_to_restart():
# Services spéciaux portant sur plusieurs machines # Services spéciaux portant sur plusieurs machines
to_add = self.__service_develop.get(serv.nom, []) to_add = self.__service_develop.get(serv.nom, [])
if to_add: if to_add:
for nom in to_add: for nom in to_add:
@ -97,13 +97,13 @@ class base_reconfigure:
else: else:
auto = False auto = False
if debug: if debug:
print 'Services à redémarrer imposés (non lecture de la base LDAP)' print 'Services à redémarrer imposés (non lecture de la base LDAP)'
for serv, args in to_do.items(): for serv, args in to_do.items():
# Au cas où le service porte sur plusieurs machines # Au cas où le service porte sur plusieurs machines
service = serv.replace('%s-' % hostname, '') service = serv.replace('%s-' % hostname, '')
if hasattr(self, service): if hasattr(self, service):
# Le service est à reconfigurer sur cette machine # Le service est à reconfigurer sur cette machine
db.services_to_restart('-%s' % serv) db.services_to_restart('-%s' % serv)
try: try:
m = getattr(self, service) m = getattr(self, service)
@ -125,17 +125,17 @@ class base_reconfigure:
if debug: if debug:
reste = db.services_to_restart() reste = db.services_to_restart()
if reste: if reste:
print "Reste à faire :" print "Reste à faire :"
for s in reste: for s in reste:
try: try:
print '\t%s' % s print '\t%s' % s
except UnicodeDecodeError: except UnicodeDecodeError:
print '\t%s: non imprimable' % s.nom print '\t%s: non imprimable' % s.nom
else: else:
print "Plus rien à faire" print "Plus rien à faire"
def _machines(self): def _machines(self):
""" Retourne les machines de la base étant 'à jour' """ """ Retourne les machines de la base étant 'à jour' """
return db.all_machines(graphic=True) return db.all_machines(graphic=True)
def _do(self, service, machines=None): def _do(self, service, machines=None):
@ -180,8 +180,8 @@ class redisdead(base_reconfigure):
def mail_modif(self, trucs): def mail_modif(self, trucs):
""" """
trucs est une liste de recherches à effectuer dans la base trucs est une liste de recherches à effectuer dans la base
l'affichage des résultats formera le corps du mail l'affichage des résultats formera le corps du mail
""" """
from supervison import mail from supervison import mail
self._do(mail(trucs)) self._do(mail(trucs))
@ -238,7 +238,7 @@ class zbee(base_reconfigure):
class komaz(base_reconfigure): class komaz(base_reconfigure):
# Mimétisme de ma part -- xhub # Mimétisme de ma part -- xhub
def __fw6(self): def __fw6(self):
if not hasattr(self, '__real_fw6'): if not hasattr(self, '__real_fw6'):
from firewall6 import Update from firewall6 import Update
@ -312,7 +312,7 @@ if __name__ == '__main__':
classe = eval(hostname) classe = eval(hostname)
args_autorises = ['quiet', 'remove=', 'add=', 'list', 'help', 'reconnect'] args_autorises = ['quiet', 'remove=', 'add=', 'list', 'help', 'reconnect']
# Ajout aussi des arguments spécifiques à la machine # Ajout aussi des arguments spécifiques à la machine
for nom in dir(classe): for nom in dir(classe):
if nom[0] != '_': if nom[0] != '_':
if len(getargspec(getattr(classe, nom))[0]) > 1: if len(getargspec(getattr(classe, nom))[0]) > 1:
@ -330,7 +330,7 @@ if __name__ == '__main__':
sys.stderr.write('%s\n' % msg) sys.stderr.write('%s\n' % msg)
sys.exit(255) sys.exit(255)
debug = 1 # défaut debug = 1 # défaut
to_do = {} to_do = {}
for opt, val in options: for opt, val in options:
@ -344,7 +344,7 @@ if __name__ == '__main__':
sys.exit(0) sys.exit(0)
elif opt == '--list': elif opt == '--list':
print 'Services à redémarrer :' print 'Services à redémarrer :'
for s in db.services_to_restart(): for s in db.services_to_restart():
try: try:
print '\t%s' % s print '\t%s' % s
@ -353,7 +353,7 @@ if __name__ == '__main__':
sys.exit(0) sys.exit(0)
elif opt == '--reconnect': elif opt == '--reconnect':
# Personnes à reconnecter # Personnes à reconnecter
print 'Recherche des personnes en fin de sanction...' print 'Recherche des personnes en fin de sanction...'
c = db.search('blacklist=*') c = db.search('blacklist=*')
services = [] services = []
@ -369,7 +369,7 @@ if __name__ == '__main__':
sys.exit(0) sys.exit(0)
elif opt == '--add': elif opt == '--add':
# Ajout d'un item dans les services à redémarrer # Ajout d'un item dans les services à redémarrer
for serv in val.split('&'): for serv in val.split('&'):
if serv.find(',') != -1: if serv.find(',') != -1:
serv, arg = serv.split(',', 1) serv, arg = serv.split(',', 1)
@ -390,5 +390,5 @@ if __name__ == '__main__':
to_do[opt[2:]] = val.split('&') to_do[opt[2:]] = val.split('&')
# On fait ce qu'il y a à faire # On fait ce qu'il y a à faire
classe(to_do) classe(to_do)

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
# Licence : GPLv2 # Licence : GPLv2
@ -13,8 +13,8 @@ from email.mime.text import MIMEText
class mail: class mail:
""" """
Envoie un mail à toutes les personnes de la liste 'To', avec les Envoie un mail à toutes les personnes de la liste 'To', avec les
informations détaillées des objets contenus dans 'objets' informations détaillées des objets contenus dans 'objets'
(instances des classes Adherent, Machine ou Club) """ (instances des classes Adherent, Machine ou Club) """
From = 'roots@crans.org' From = 'roots@crans.org'
@ -25,14 +25,14 @@ class mail:
To: %(To)s To: %(To)s
Subject: %(Subject)s Subject: %(Subject)s
Mime-Version: 1.0 Mime-Version: 1.0
Content-Type: text/plain; charset="iso-8859-1" Content-Type: text/plain; charset="utf-8"
Content-Disposition: inline Content-Disposition: inline
Content-Transfer-Encoding: 8bit Content-Transfer-Encoding: 8bit
%(Text)s""" %(Text)s"""
# Avec les caractères d'échappement qui vont bien pour la couleur ? # Avec les caractères d'échappement qui vont bien pour la couleur ?
couleur = False couleur = False
def __init__(self,recherches) : def __init__(self,recherches) :
@ -96,7 +96,7 @@ Subject: %(Subject)s
%(Text)s""" %(Text)s"""
# Avec les caractères d'échappement qui vont bien pour la couleur ? # Avec les caractères d'échappement qui vont bien pour la couleur ?
couleur = False couleur = False
def __init__(self,modifs) : def __init__(self,modifs) :

12
gestion/gen_confs/surveillance.py Normal file → Executable file
View file

@ -1,11 +1,11 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" """
Classe de synchronisation entre la base ldap et Classe de synchronisation entre la base ldap et
la base postgresql pour la liste des exemptions la base postgresql pour la liste des exemptions
et la liste des machines. et la liste des machines.
Utilisé par generate.py Utilisé par generate.py
""" """
# importation des fonctions et classes # importation des fonctions et classes
@ -18,7 +18,7 @@ import psycopg2
db = crans_ldap() db = crans_ldap()
# Génération des la tables d'exemptions # Génération des la tables d'exemptions
####################################### #######################################
class exemptions(gen_config) : class exemptions(gen_config) :
@ -49,7 +49,7 @@ class exemptions(gen_config) :
pgsql.commit() pgsql.commit()
# Génération des la liste des machines # Génération des la liste des machines
###################################### ######################################
class machines(gen_config) : class machines(gen_config) :
@ -70,7 +70,7 @@ class machines(gen_config) :
# machines = self.machines # machines = self.machines
# machines = db.search('ip=*')['machine'] # machines = db.search('ip=*')['machine']
# connexion à la base postgresql # connexion à la base postgresql
import psycopg2 import psycopg2
pgsql = psycopg2.connect(database='filtrage', user='crans') pgsql = psycopg2.connect(database='filtrage', user='crans')
curseur = pgsql.cursor() curseur = pgsql.cursor()
@ -82,7 +82,7 @@ class machines(gen_config) :
ipv6_vu[ipv6] = True ipv6_vu[ipv6] = True
return ret return ret
# ajout des entrée # ajout des entrée
for m in machines: for m in machines:
if m.proprietaire().__class__ == Club: if m.proprietaire().__class__ == Club:
curseur.execute("INSERT INTO machines (ip, type, id) VALUES (inet'%s','club',%s);"%(m.ip(),m.proprietaire().id())) curseur.execute("INSERT INTO machines (ip, type, id) VALUES (inet'%s','club',%s);"%(m.ip(),m.proprietaire().id()))

View file

@ -500,7 +500,7 @@ aaa port-access mac-based %(prise)s unauth-vid 1
return ','.join(result) return ','.join(result)
# Saut de ligne parasite # Saut de ligne parasite
params['INTERFACES_CONF'] = params['INTERFACES_CONF'][:-1].encode('iso-8859-15') params['INTERFACES_CONF'] = params['INTERFACES_CONF'][:-1].encode('utf-8')
# Conversion des listes # Conversion des listes
for key in [ 'uplinks', 'non_uplinks' ] : for key in [ 'uplinks', 'non_uplinks' ] :

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import time, commands import time, commands
from gen_confs import gen_config, ERREUR, OK, anim from gen_confs import gen_config, ERREUR, OK, anim
@ -9,11 +9,11 @@ sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, BorneWifi from ldap_crans import crans_ldap, BorneWifi
class conf_wifi_ng(gen_config) : class conf_wifi_ng(gen_config) :
""" Génération de la configuration de isakmpd dans ISAKMPD_CONF """ Génération de la configuration de isakmpd dans ISAKMPD_CONF
Le fichier est constitué en 5 parties : Le fichier est constitué en 5 parties :
1) Configuration générale insérée telle quelle 1) Configuration générale insérée telle quelle
2) Phase 1 : une ligne par host suivant template 2) Phase 1 : une ligne par host suivant template
3) Phase 2 : une entrée par machine 3) Phase 2 : une entrée par machine
4) Bloc par machine suivant template 4) Bloc par machine suivant template
5) Ajout de net_crans 5) Ajout de net_crans
@ -21,8 +21,8 @@ class conf_wifi_ng(gen_config) :
""" """
######################################PARTIE DE CONFIGURATION ######################################PARTIE DE CONFIGURATION
# Fichiers à écrire # Fichiers à écrire
# Répertoire d'écriture des fichiers de zone # Répertoire d'écriture des fichiers de zone
ISAKMPD_CONF='/etc/isakmpd/isakmpd.conf' ISAKMPD_CONF='/etc/isakmpd/isakmpd.conf'
# Correspondance MAC/IP # Correspondance MAC/IP
MACIP='/etc/wifi/wifi-update-ng/common/etc/macip' MACIP='/etc/wifi/wifi-update-ng/common/etc/macip'
@ -57,7 +57,7 @@ class conf_wifi_ng(gen_config) :
self.anim=anim('\tfin reconfigurations') self.anim=anim('\tfin reconfigurations')
def gen_bornes(self, bornes): def gen_bornes(self, bornes):
"""Génération de la configuration des bornes""" """Génération de la configuration des bornes"""
TARGET = "/var/www/wifi-update" TARGET = "/var/www/wifi-update"
WORK = "%s/work" % TARGET WORK = "%s/work" % TARGET
@ -68,20 +68,20 @@ class conf_wifi_ng(gen_config) :
if self._bornes and borne.nom().split(".")[0] not in self._bornes: if self._bornes and borne.nom().split(".")[0] not in self._bornes:
continue continue
self.anim=anim('\treconfiguration de %s' % borne.nom()) self.anim=anim('\treconfiguration de %s' % borne.nom())
# Il s'agit de faire l'union du répertoire common et du # Il s'agit de faire l'union du répertoire common et du
# répertoire propre (s'il existe) ou alors du répertoire default # répertoire propre (s'il existe) ou alors du répertoire default
# On supprime le répertoire de travail # On supprime le répertoire de travail
if os.path.isdir(WORK): if os.path.isdir(WORK):
shutil.rmtree(WORK) shutil.rmtree(WORK)
# On copie COMMON # On copie COMMON
shutil.copytree(COMMON, WORK) shutil.copytree(COMMON, WORK)
# Est-ce qu'un répertoire spécifique existe ? # Est-ce qu'un répertoire spécifique existe ?
top = os.path.join(ROOT, borne.nom()) top = os.path.join(ROOT, borne.nom())
if not os.path.isdir(top): if not os.path.isdir(top):
top = DEFAULT top = DEFAULT
# On en copie aussi le contenu # On en copie aussi le contenu
for root, dirs, files in os.walk(top, topdown=True): for root, dirs, files in os.walk(top, topdown=True):
# On créé les répertoires # On créé les répertoires
for name in dirs: for name in dirs:
try: try:
os.mkdir(os.path.join("%s%s" % (WORK, root[len(top):]), os.mkdir(os.path.join("%s%s" % (WORK, root[len(top):]),
@ -93,7 +93,7 @@ class conf_wifi_ng(gen_config) :
shutil.copy(os.path.join(root, name), shutil.copy(os.path.join(root, name),
os.path.join("%s%s" % (WORK, root[len(top):]), os.path.join("%s%s" % (WORK, root[len(top):]),
name)) name))
# On créé/complète le fichier /etc/nvram.updates # On créé/complète le fichier /etc/nvram.updates
if isinstance(borne, BorneWifi) and borne.nom() != "non-configure.wifi.crans.org": if isinstance(borne, BorneWifi) and borne.nom() != "non-configure.wifi.crans.org":
fd = file(os.path.join(WORK, "etc", "nvram.updates"), "a") fd = file(os.path.join(WORK, "etc", "nvram.updates"), "a")
data = { 'HOST': borne.nom().split('.')[0], data = { 'HOST': borne.nom().split('.')[0],
@ -113,7 +113,7 @@ NVRAM_wl0_radio=%(ON)d
NVRAM_crans_hotspot=%(HOTSPOT)d NVRAM_crans_hotspot=%(HOTSPOT)d
""" % data) """ % data)
# On complète par les variables de la NVRAM # On complète par les variables de la NVRAM
for info in borne.nvram(): for info in borne.nvram():
fd.write('variables="${variables} %s"\n' % info.split("=")[0]) fd.write('variables="${variables} %s"\n' % info.split("=")[0])
fd.write("NVRAM_%s\n" % info) fd.write("NVRAM_%s\n" % info)
@ -122,15 +122,15 @@ NVRAM_crans_hotspot=%(HOTSPOT)d
# On fait du menage # On fait du menage
os.system("find %s -name CVS -type d -exec rm -rf {} \\; 2> /dev/null" % WORK) os.system("find %s -name CVS -type d -exec rm -rf {} \\; 2> /dev/null" % WORK)
os.system("find %s -name '*~' -type f -exec rm -f {} \\;" % WORK) os.system("find %s -name '*~' -type f -exec rm -f {} \\;" % WORK)
# Ensuite, on créé le tar # Ensuite, on créé le tar
os.system("tar zcf %s/%s.tmp.tar.gz -C %s ." % (TARGET, borne.nom(), WORK)) os.system("tar zcf %s/%s.tmp.tar.gz -C %s ." % (TARGET, borne.nom(), WORK))
# Et on le renomme (on espère que c'est atomique) # Et on le renomme (on espère que c'est atomique)
os.rename("%s/%s.tmp.tar.gz" % (TARGET, borne.nom()), os.rename("%s/%s.tmp.tar.gz" % (TARGET, borne.nom()),
"%s/%s.tar.gz" % (TARGET, borne.nom())) "%s/%s.tar.gz" % (TARGET, borne.nom()))
print OK print OK
def gen_macip(self, clients, bornes): def gen_macip(self, clients, bornes):
"""Génération de la correspondance MAC/IP""" """Génération de la correspondance MAC/IP"""
self.anim=anim('\r\tFichier MAC/IP',len(clients + bornes)) self.anim=anim('\r\tFichier MAC/IP',len(clients + bornes))
fd = file(self.MACIP, "w") fd = file(self.MACIP, "w")
for machine in clients + bornes: for machine in clients + bornes:
@ -141,9 +141,9 @@ NVRAM_crans_hotspot=%(HOTSPOT)d
print OK print OK
def gen_isakmpd(self, clients): def gen_isakmpd(self, clients):
"""Génération du fichier pour isakmpd""" """Génération du fichier pour isakmpd"""
# Config générale de ISAKMPd # Config générale de ISAKMPd
general=""" general="""
[General] [General]
Listen-on= 138.231.148.1 Listen-on= 138.231.148.1
@ -202,7 +202,7 @@ Remote-ID= Net-%(HOST)s
ID-type= IPV4_ADDR ID-type= IPV4_ADDR
Address= %(IP)s Address= %(IP)s
""" """
# Dernière partie du fichier # Dernière partie du fichier
net_crans=""" net_crans="""
[Net-crans] [Net-crans]
ID-type= IPV4_ADDR_SUBNET ID-type= IPV4_ADDR_SUBNET
@ -226,7 +226,7 @@ Netmask= 0.0.0.0
# Phase 2 # Phase 2
if blocs != '' : if blocs != '' :
# Ce n'est pas la première machine, il faut insérer un séparateur # Ce n'est pas la première machine, il faut insérer un séparateur
phase2 += phase2_sep phase2 += phase2_sep
phase2 += phase2_template % data phase2 += phase2_template % data

View file

@ -51,7 +51,7 @@ droits = db.search("uid=%s" % script_utilisateur)['adherent'][0].droits()
isimprimeur = u"Imprimeur" in droits isimprimeur = u"Imprimeur" in droits
iscontroleur = u'Tresorier' in droits iscontroleur = u'Tresorier' in droits
isbureau = u'Bureau' in droits isbureau = u'Bureau' in droits
encoding = sys.stdin.encoding or 'ISO-8859-15' encoding = sys.stdin.encoding or 'UTF-8'
if u'Nounou' in droits: if u'Nounou' in droits:
if os.path.exists(os.path.expanduser('~/.dialogrc')): if os.path.exists(os.path.expanduser('~/.dialogrc')):
@ -1892,7 +1892,7 @@ def select(clas, quoi, mde=''):
s= ['', '', '', '', '', '', '', '', '', ''] s= ['', '', '', '', '', '', '', '', '', '']
def f(a): def f(a):
try: try:
return unicode(a, 'iso-8859-15') return unicode(a, 'utf-8')
except: except:
return a return a
while 1: while 1:

View file

@ -182,7 +182,7 @@ def preattr(val):
val = str(val).strip() val = str(val).strip()
# On passe tout en utf-8 pour ne pas avoir de problèmes # On passe tout en utf-8 pour ne pas avoir de problèmes
# d'accents dans la base # d'accents dans la base
return [len(val), unicode(val, 'iso-8859-1').encode('utf-8')] return [len(val), val]
elif isinstance(val, unicode): elif isinstance(val, unicode):
val = val.strip() val = val.strip()
return [len(val), val.encode('utf-8')] return [len(val), val.encode('utf-8')]
@ -690,8 +690,7 @@ class CransLdap:
closelog() closelog()
if type(expression) == str: if type(expression) == str:
# Transformation de l'expression en utf-8 pass
expression = unicode(expression, 'iso-8859-15').encode('utf-8')
elif type(expression) == unicode: elif type(expression) == unicode:
expression = expression.encode('utf-8') expression = expression.encode('utf-8')
else: else:
@ -1889,7 +1888,7 @@ class BaseProprietaire(BaseClasseCrans):
if self.idn !='cid': if self.idn !='cid':
# Mail de bienvenue # Mail de bienvenue
self.services_to_restart('mail_bienvenue', [self.mail().encode('iso-8859-15')], start = time.time() + 660) self.services_to_restart('mail_bienvenue', [self.mail().encode('utf-8')], start = time.time() + 660)
else: else:
ret += coul(u"Modification %s effectuée avec succès." % self.Nom(), 'vert') ret += coul(u"Modification %s effectuée avec succès." % self.Nom(), 'vert')
@ -2178,7 +2177,7 @@ class Adherent(BaseProprietaire):
self.mail_invalide(False) self.mail_invalide(False)
# on renvoie le mail de bienvenue # on renvoie le mail de bienvenue
self.services_to_restart('mail_bienvenue', [new.encode('iso-8859-15')]) self.services_to_restart('mail_bienvenue', [new.encode('utf-8')])
return new return new
@ -2876,7 +2875,7 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
def __host_alias(self, champ, new): def __host_alias(self, champ, new):
""" Vérification de la validité d'un nom de machine """ """ Vérification de la validité d'un nom de machine """
# Supression des accents # Supression des accents
new = strip_accents(unicode(new, 'iso-8859-15')) new = strip_accents(unicode(new, 'utf-8'))
l, new = preattr(new) l, new = preattr(new)
new = new.lower() new = new.lower()

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys

View file

@ -72,7 +72,7 @@ par le script.
s = smtplib.SMTP() s = smtplib.SMTP()
s.connect('smtp.crans.org') s.connect('smtp.crans.org')
for adherent in adherents: for adherent in adherents:
mail = adherent.mail().encode("iso-8859-15", "ignore") mail = adherent.mail().encode("utf-8", "ignore")
if "@" not in mail: if "@" not in mail:
mail = mail + "@crans.org" mail = mail + "@crans.org"
cprint(u"Envoi du mail à %s <%s>..." % (adherent.Nom(), mail)) cprint(u"Envoi du mail à %s <%s>..." % (adherent.Nom(), mail))

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
@ -15,7 +15,7 @@ for m in machines :
# texte pour la machine # texte pour la machine
txt = u'' txt = u''
txt += u'Propriétaire : %s\n' % m.proprietaire().Nom() txt += u'Propriétaire : %s\n' % m.proprietaire().Nom()
txt += u'Machine : %s\n' % m.nom() txt += u'Machine : %s\n' % m.nom()
txt += u'destination : %s\n' % ', '.join(m.exempt()) txt += u'destination : %s\n' % ', '.join(m.exempt())

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
@ -13,7 +13,7 @@ done = []
txts = [] txts = []
for m in machines : for m in machines :
# on vérifie qu'on l'a pas encore traité # on vérifie qu'on l'a pas encore traité
if m.ip() in done : if m.ip() in done :
continue continue
if m.proprietaire().__class__ == AssociationCrans : if m.proprietaire().__class__ == AssociationCrans :
@ -22,7 +22,7 @@ for m in machines :
# texte pour la machine # texte pour la machine
txt = u'' txt = u''
txt += u'Propriétaire : %s\n' % m.proprietaire().Nom() txt += u'Propriétaire : %s\n' % m.proprietaire().Nom()
txt += u'Machine : %s\n' % m.nom() txt += u'Machine : %s\n' % m.nom()
if m.portTCPin() : if m.portTCPin() :
txt += u'ports TCP in : %s\n' % ' '.join(m.portTCPin()) txt += u'ports TCP in : %s\n' % ' '.join(m.portTCPin())

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
from commands import getoutput from commands import getoutput

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
@ -15,7 +15,7 @@ for a in adherents :
if a.solde() == 0 : if a.solde() == 0 :
continue continue
# texte pour l'adhérent # texte pour l'adhérent
txt = u'' txt = u''
txt += u'Nom : %s\n' % a.Nom() txt += u'Nom : %s\n' % a.Nom()
txt += u'Solde : %s\n' % a.solde() txt += u'Solde : %s\n' % a.solde()

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
@ -12,11 +12,11 @@ def titre (bat) :
if bat == 'P' : if bat == 'P' :
return 'Pavillon des jardins' return 'Pavillon des jardins'
elif bat == '?' : elif bat == '?' :
return 'Autres (extérieurs et chambres invalides)' return 'Autres (extérieurs et chambres invalides)'
else : else :
return 'Bâtiment %s' % bat return 'Bâtiment %s' % bat
# création de la liste vide # création de la liste vide
########################### ###########################
liste = {} liste = {}
@ -26,7 +26,7 @@ for bat in bats + '?' :
# remplissage de la liste # remplissage de la liste
######################### #########################
# les extérieurs # les extérieurs
adhs = db.search( 'paiement=ok&etudes!=Pers' )['adherent'] adhs = db.search( 'paiement=ok&etudes!=Pers' )['adherent']
for adh in adhs : for adh in adhs :
bat = adh.chbre()[0] bat = adh.chbre()[0]
@ -34,7 +34,7 @@ for adh in adhs :
bat = '?' bat = '?'
liste[bat].append( u'%s %s' % ( adh.nom(), adh.prenom() ) ) liste[bat].append( u'%s %s' % ( adh.nom(), adh.prenom() ) )
# création du fichier tex # création du fichier tex
######################### #########################
print """\\documentclass[a4paper,11pt]{article} print """\\documentclass[a4paper,11pt]{article}
@ -61,7 +61,7 @@ for bat in bats + '?' :
\\hline \\hline
\\endhead""" % {'bat' : titre(bat) } \\endhead""" % {'bat' : titre(bat) }
# ajout des adhérents # ajout des adhérents
liste[bat].sort() liste[bat].sort()
for adh in liste[bat] : for adh in liste[bat] :
print (u'%s& \\\\\n\\hline' % adh).encode('iso 8859-15') print (u'%s& \\\\\n\\hline' % adh).encode('iso 8859-15')

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys import sys
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
@ -10,21 +10,21 @@ from affich_tools import coul
import threading import threading
from os import getuid from os import getuid
# il faut être root # il faut être root
if getuid() : if getuid() :
print 'Il faut être root !' print 'Il faut être root !'
sys.exit(1) sys.exit(1)
# connexion à la base de données # connexion à la base de données
db = crans_ldap() db = crans_ldap()
# décompostion des arguments # décompostion des arguments
try : try :
mac = ":".join([i.zfill(2) for i in sys.argv[1].split(":")]).upper() mac = ":".join([i.zfill(2) for i in sys.argv[1].split(":")]).upper()
except : except :
mac = None mac = None
# dit si une mac a déja été traitée # dit si une mac a déja été traitée
mac_done=[] mac_done=[]
def done (mac) : def done (mac) :
global mac_done global mac_done
@ -34,7 +34,7 @@ def done (mac) :
mac_done.append(mac) mac_done.append(mac)
return False return False
# liste des résultats # liste des résultats
results = [] results = []
# classe d'interrogation des bornes # classe d'interrogation des bornes

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
import sys, re import sys, re
from time import sleep from time import sleep
@ -37,11 +37,11 @@ class interroge_switch (threading.Thread) :
if (prise != None): if (prise != None):
nom=sw.nom(None,prise) nom=sw.nom(None,prise)
if self.affiche_uplinks or "uplink" not in nom: if self.affiche_uplinks or "uplink" not in nom:
self.reponse = ("%-10s => prise %-2s : %s" % (self.switch.encode('iso-8859-15').replace('.adm.crans.org',''), str(prise), nom)) self.reponse = ("%-10s => prise %-2s : %s" % (self.switch.encode('utf-8').replace('.adm.crans.org',''), str(prise), nom))
# Retourne les infos sur la machine (l'équivalent d'un whos, mais renvoie la # Retourne les infos sur la machine (l'équivalent d'un whos, mais renvoie la
# chaîne de caractères) # chaîne de caractères)
def info_machine(mac): def info_machine(mac):
s = [] s = []
db = crans_ldap() db = crans_ldap()
@ -52,7 +52,7 @@ def info_machine(mac):
r = re.sub('\x1b\[1;([0-9]|[0-9][0-9])m', '', r) r = re.sub('\x1b\[1;([0-9]|[0-9][0-9])m', '', r)
s.append(r) s.append(r)
if len(machines) == 0: if len(machines) == 0:
s.append(u"Recherche LDAP de la MAC %s : aucune machine trouvée\n" % mac) s.append(u"Recherche LDAP de la MAC %s : aucune machine trouvée\n" % mac)
return u"\n".join(s) return u"\n".join(s)
@ -66,7 +66,7 @@ def trace_machine(mac, affiche_uplinks=False):
for t in tableau: for t in tableau:
t.join() t.join()
resultat = u'Traçage de %s...\n' % mac resultat = u'Traçage de %s...\n' % mac
tracage = u'' tracage = u''
for t in tableau: for t in tableau:

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- encoding: iso-8859-15 -*- # -*- encoding: utf-8 -*-
# Stats sur les historiques # Stats sur les historiques
@ -13,22 +13,22 @@ import re
from time import mktime, strptime from time import mktime, strptime
def plat(chose): def plat(chose):
"""Applatit une liste de liste. Hautement récursif.""" """Applatit une liste de liste. Hautement récursif."""
if type(chose) != ListType: if type(chose) != ListType:
return [chose] return [chose]
return sum(map(lambda x: plat(x), chose), []) return sum(map(lambda x: plat(x), chose), [])
def hist(): def hist():
"""Récupère l'historique dans une base SQLite dont la connexion est returnée.""" """Récupère l'historique dans une base SQLite dont la connexion est returnée."""
# On récupèr les adhérents # On récupèr les adhérents
adherents = crans_ldap().search("nom=*")['adherent'] adherents = crans_ldap().search("nom=*")['adherent']
# Et les historiques rattachés à eux et à leurs machines # Et les historiques rattachés à eux et à leurs machines
historiques = map(lambda x: [x.historique(), map(lambda y: y.historique(), x.machines())], historiques = map(lambda x: [x.historique(), map(lambda y: y.historique(), x.machines())],
adherents) adherents)
historiques = plat(historiques) historiques = plat(historiques)
# On va maintenant coller les historiques dans une structure plus # On va maintenant coller les historiques dans une structure plus
# sympa, style une base SQL que l'on garde en mémoire # sympa, style une base SQL que l'on garde en mémoire
con = sqlite.connect("historiques") con = sqlite.connect("historiques")
cur = con.cursor() cur = con.cursor()
cur.execute("CREATE TABLE historique (date INTEGER, nom TEXT, action TEXT)") cur.execute("CREATE TABLE historique (date INTEGER, nom TEXT, action TEXT)")

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
# High level interface between XEN
# and XEN user

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
# ############################################################# # #############################################################
# .. # ..
# .... ............ ........ # .... ............ ........
@ -28,7 +28,7 @@
Copyright (c) 2006 by www.crans.org Copyright (c) 2006 by www.crans.org
""" """
# Début : Ajout log pour réestimer les coûts # Début : Ajout log pour réestimer les coûts
import time import time
# Fin # Fin
import sys, tempfile, os, commands, shutil, syslog, stat import sys, tempfile, os, commands, shutil, syslog, stat
@ -48,7 +48,7 @@ COUT_UNITE_NOIRE = config.impression.c_noir
COUT_PASSAGE_TAMBOUR_NOIR = config.impression.c_tambour_noir COUT_PASSAGE_TAMBOUR_NOIR = config.impression.c_tambour_noir
COUT_PASSAGE_TAMBOUR_COULEUR = config.impression.c_tambour_coul COUT_PASSAGE_TAMBOUR_COULEUR = config.impression.c_tambour_coul
# Début : Ajout log pour réestimer les coûts # Début : Ajout log pour réestimer les coûts
FICHIER_LOG="/var/log/log_couts/estimations" FICHIER_LOG="/var/log/log_couts/estimations"
# Fin # Fin
@ -88,10 +88,10 @@ def try_command(cmd, tmp_rep, error_msg):
def base_prix(path_pdf_file, color=False): def base_prix(path_pdf_file, color=False):
u""" Calcul le prix d'une impression couleur ou noir et blanc sur papier A4 """ u""" Calcul le prix d'une impression couleur ou noir et blanc sur papier A4 """
# nom_rep seras le dossier dans tmp ou tous les fichier créé par # nom_rep seras le dossier dans tmp ou tous les fichier créé par
# convert seront entreposé # convert seront entreposé
nom_rep = tempfile.mkdtemp(prefix='tmpimpr') nom_rep = tempfile.mkdtemp(prefix='tmpimpr')
nom_png = "%s/convert.png" % nom_rep # Nom prefixe et chemin des png créé par convert nom_png = "%s/convert.png" % nom_rep # Nom prefixe et chemin des png créé par convert
escaped_path_pdf_file = escapeForShell(path_pdf_file) escaped_path_pdf_file = escapeForShell(path_pdf_file)
escaped_path_ps_file = escapeForShell(path_pdf_file + ".ps") escaped_path_ps_file = escapeForShell(path_pdf_file + ".ps")
error_msg = "ERREUR %%d : Fichier invalide. Aucun %s cree." error_msg = "ERREUR %%d : Fichier invalide. Aucun %s cree."
@ -113,14 +113,14 @@ def base_prix(path_pdf_file, color=False):
nom_rep, nom_rep,
error_msg % "ps") error_msg % "ps")
# Convertit les ps en png (il est néscessaire de passer par un ps # Convertit les ps en png (il est néscessaire de passer par un ps
# car ghostscript refuse certain pdf) # car ghostscript refuse certain pdf)
try_command("nice -n 5 gs -sDEVICE=%s -r30 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile=%s%%d -q %s" % try_command("nice -n 5 gs -sDEVICE=%s -r30 -dBATCH -dNOPAUSE -dSAFER -dPARANOIDSAFER -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dMaxBitmap=50000000 -sOutputFile=%s%%d -q %s" %
(gs_device, nom_png, escaped_path_ps_file), (gs_device, nom_png, escaped_path_ps_file),
nom_rep, nom_rep,
error_msg % "png") error_msg % "png")
# Récupère la liste des fichiers # Récupère la liste des fichiers
list_filepng=os.listdir(nom_rep) list_filepng=os.listdir(nom_rep)
# Calcule le nombre de pixel # Calcule le nombre de pixel
remplissage = [0] * (nb_composante + 1) # couleurs (N ou CMJN), nombre de pages remplissage = [0] * (nb_composante + 1) # couleurs (N ou CMJN), nombre de pages
@ -146,7 +146,7 @@ def base_prix(path_pdf_file, color=False):
c_total = (COUT_PASSAGE_TAMBOUR_NOIR * faces # passage dans les toners c_total = (COUT_PASSAGE_TAMBOUR_NOIR * faces # passage dans les toners
+ COUT_UNITE_NOIRE * total_noir) # cout encre noire + COUT_UNITE_NOIRE * total_noir) # cout encre noire
# Début : Ajout log pour réestimer les coûts # Début : Ajout log pour réestimer les coûts
fichier_log_est=open(FICHIER_LOG,"a") fichier_log_est=open(FICHIER_LOG,"a")
fichier_log_est.write("%d %d %3d %10.3f %10.3f %s\n" % (time.time(), color, faces, total_noir, total_couleur, path_pdf_file) ) fichier_log_est.write("%d %d %3d %10.3f %10.3f %s\n" % (time.time(), color, faces, total_noir, total_couleur, path_pdf_file) )
fichier_log_est.close() fichier_log_est.close()

View file

@ -1,9 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" """
etat_imprimante.py etat_imprimante.py
Récupère, filtre et formate l'état actuel de l'imprimante Récupère, filtre et formate l'état actuel de l'imprimante
Copyright (c) 2006, 2007, 2008, 2009 by Cr@ns (http://www.crans.org) Copyright (c) 2006, 2007, 2008, 2009 by Cr@ns (http://www.crans.org)
@ -28,7 +28,7 @@ def etat_canon():
'printing(4)\nrunning(2)' : u'Impression en cours', 'printing(4)\nrunning(2)' : u'Impression en cours',
'other(1)\ndown(5)' : u"Imprimante hors-service", 'other(1)\ndown(5)' : u"Imprimante hors-service",
'other(1)\nrunning(2)' : u'Imprimante en veille', 'other(1)\nrunning(2)' : u'Imprimante en veille',
'warmup(5)\nrunning(2)' : u'Préchauffage', 'warmup(5)\nrunning(2)' : u'Préchauffage',
'idle(3)\nwarning(3)' : u'Imprimante fonctionnelle', 'idle(3)\nwarning(3)' : u'Imprimante fonctionnelle',
'printing(4)\nwarning(3)' : u'Impression en cours' 'printing(4)\nwarning(3)' : u'Impression en cours'
} }
@ -53,15 +53,15 @@ def etat_canon():
def etat_laserjet(): def etat_laserjet():
""" Renvoie une liste des differents ecrans actuels du display de l'imprimante """ """ Renvoie une liste des differents ecrans actuels du display de l'imprimante """
_dico = { _dico = {
u"READY": u"Prête", u"READY": u"Prête",
u"PrÁt": u"Prêt", u"PrÁt": u"Prêt",
u"Pr menus, appuy \x1e": u"", u"Pr menus, appuy \x1e": u"",
u"Powersave activÅ": u"En veille", u"Powersave activÅ": u"En veille",
u"Verification": u"Vérification imprimante", u"Verification": u"Vérification imprimante",
u"imprimante": u"", u"imprimante": u"",
u"PrÅchauffage": u"Préchauffage", u"PrÅchauffage": u"Préchauffage",
u"Traitement de la": u"Impression en cours", u"Traitement de la": u"Impression en cours",
u"tÀche du bac 4": u"", u"tÀche du bac 4": u"",
u"COMMANDER CARTOUCHE": u"", u"COMMANDER CARTOUCHE": u"",
u"COMMANDER KIT NETTOY": u"", u"COMMANDER KIT NETTOY": u"",
u"COMMANDER FOURNIT.": u"", u"COMMANDER FOURNIT.": u"",

View file

@ -1,3 +1,3 @@
#! /bin/sh #! /bin/sh
LANG=fr_FR@euro sudo -u respbats /usr/scripts/gestion/gest_crans.py $* LANG=fr_FR.UTF-8 sudo -u respbats /usr/scripts/gestion/gest_crans.py $*

View file

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
#execution avec des droits suffisants #execution avec des droits suffisants
LANG=fr_FR@euro sudo -u '#120' /usr/scripts/gestion/tools/locate_mac.py $* LANG=fr_FR.UTF-8 sudo -u '#120' /usr/scripts/gestion/tools/locate_mac.py $*

View file

@ -1,4 +1,3 @@
#! /bin/sh #! /bin/sh
#LANG=fr_FR@euro
sudo -u respbats /usr/scripts/gestion/logreader/rsyslog_reader.py $* sudo -u respbats /usr/scripts/gestion/logreader/rsyslog_reader.py $*

View file

@ -1,3 +1,3 @@
#! /bin/sh #! /bin/sh
LANG=fr_FR@euro sudo -u respbats /usr/scripts/gestion/ressuscite.py $* LANG=fr_FR.UTF-8 sudo -u respbats /usr/scripts/gestion/ressuscite.py $*

View file

@ -1,3 +1,3 @@
#!/bin/sh #!/bin/sh
LANG=fr_FR@euro sudo -u respbats /usr/scripts/gestion/whos.py $* LANG=fr_FR.UTF-8 sudo -u respbats /usr/scripts/gestion/whos.py $*

View file

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
#execution avec des droits suffisants #execution avec des droits suffisants
LANG=fr_FR@euro sudo -u 'arpwatch' /usr/scripts/surveillance/arpwatch_sendmail.py $* LANG=fr_FR.UTF-8 sudo -u 'arpwatch' /usr/scripts/surveillance/arpwatch_sendmail.py $*

View file

@ -1,49 +1,149 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- encoding: utf-8 -*-
# Ajout d'un whos et d'un tracage aux mails d'arpwatch
# Auteurs : Stéphane Glondu, Cyril Cohen
# Licence : GPLv2
import sys, os, re, smtplib
from commands import getstatusoutput
sys.path.append('/usr/scripts/gestion/tools')
from locate_mac import trace_machine, format_mac, info_machine
find_mac = re.compile(r'[0-9A-Fa-f]{1,2}(?::[0-9A-Fa-f]{1,2}){5}')
def get_machine(unformated_mac): ###########################
mac = format_mac(unformated_mac) # Import des commmandes : #
return u"\n" + info_machine(mac) + u"\n" + trace_machine(mac) ###########################
import commands
import os
# import pg # Import des commandes de postgres
import sys
sys.path.append('/usr/scripts/gestion')
import iptools
import psycopg2
import re
sys.path.append('/usr/script/surveillance')
import strptime
# Définition de constantes :
############################
reseau = ["138.231.136.0/21", "138.231.148.0/22"]
# Ouverture de la base de données :
###################################
pgsql = psycopg2.connect(host='pgsql.adm.crans.org', database='filtrage', user='crans')
# Ancienne méthode pour faire de l'autocommit.
# Sous wheezy, il faudra remplacer par pgsql.set_session(autocommit=True) !!!
pgsql.set_isolation_level(0)
curseur = pgsql.cursor()
if __name__ == "__main__": ###########################################
texte = sys.stdin.read() #.decode('ISO-8859-15') # Récupération des tables de protocoles : #
textes = texte.splitlines(True) ###########################################
i = textes.index(u'\n')
textes[i-1:i-1] = [
u'MIME-Version: 1.0\n',
u'Content-Type: text/plain; charset=UTF-8\n',
u'Content-Transfer-Encoding: 8bit\n',
]
# On récupère les destinataires dans les arguments (très ad hoc) requete = "SELECT nom,id_p2p from protocole_p2p"
recipients = sys.argv[2].split(',') curseur.execute(requete)
# On complète le message curseur.fetchall
tableau = curseur.fetchall()
protocole_p2p = {}
for cellule in tableau:
protocole_p2p[cellule[0]]=cellule[1]
requete = "SELECT nom,id from protocole"
curseur.execute(requete)
curseur.fetchall
tableau = curseur.fetchall()
protocole = {}
for cellule in tableau:
protocole[cellule[0]]=cellule[1]
##############################################################
# Parser ler log du firewall: /var/log/firewall/filtre.log : #
##############################################################
# Définition des motifs des comparaisons :
##########################################
motif_p2p = re.compile("^(.*) komaz .* IPP2P=([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
motif_virus = re.compile("^(.*) komaz .* Virus:([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
motif_flood = re.compile("^(.*) komaz .* Flood:([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
# On récupère en continu les log du firewall:
#############################################
filtre = os.popen("tail -F /var/log/firewall/filtre.log 2> /dev/null")
# On matche les log du firewall avec les motifs :
#################################################
for log in filtre:
resultat_p2p = motif_p2p.match(log)
resultat_virus = motif_virus.match(log)
resultat_flood = motif_flood.match(log)
if resultat_p2p :
try: try:
macs = find_mac.findall(texte) ip_src = resultat_p2p.group(3)
for mac in macs: verif = iptools.AddrInNets (ip_src,reseau)
textes.append(get_machine(mac)) except ValueError:
except: continue #IP malformee
# En cas d'exception, on envoie le traceback if verif :
import traceback try:
textes.append(u'\n') date = resultat_p2p.group(1)
textes.append(u''.join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))) id_p2p = int(protocole_p2p[resultat_p2p.group(2)])
textes.append('\n-- \narpwatch_sendmail.py\n') ip_src = resultat_p2p.group(3)
ip_dest = resultat_p2p.group(4)
proto = int(protocole[resultat_p2p.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_p2p.group(6))
port_dest = int(resultat_p2p.group(7))
date=strptime.syslog2pgsql(date)
except ValueError, KeyError:
continue #mal parse
smtp = smtplib.SMTP() # On remplit la base :
smtp.connect() ######################
smtp.sendmail("arpwatch@crans.org", recipients, u''.join(textes).encode('UTF-8')) requete = "INSERT INTO p2p (date,ip_src,ip_dest,id_p2p,id,port_src,port_dest) VALUES ('%s','%s','%s',%d,%d,%d,%d)" % (date,ip_src,ip_dest,id_p2p,proto,port_src,port_dest)
smtp.quit() curseur.execute(requete)
# On teste si le log contient des virus
########################################
elif resultat_virus :
try:
ip_src = resultat_virus.group(3)
verif = iptools.AddrInNets (ip_src,reseau)
except ValueError:
continue
if verif :
try:
date = resultat_virus.group(1)
ip_src = resultat_virus.group(3)
ip_dest = resultat_virus.group(4)
proto = int(protocole[resultat_virus.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_virus.group(6))
port_dest = int(resultat_virus.group(7))
# On remplit la base :
######################
date=strptime.syslog2pgsql(date)
except ValueError, KeyError:
continue
requete = "INSERT INTO virus (date,ip_src,ip_dest,id,port_src,port_dest) VALUES ('%s','%s','%s',%d,%d,%d)" % (date,ip_src,ip_dest,proto,port_src,port_dest)
curseur.execute(requete)
elif resultat_flood :
try:
ip_src = resultat_flood.group(3)
verif = iptools.AddrInNets (ip_src,reseau)
except ValueError:
continue
if verif :
try:
date = resultat_flood.group(1)
ip_src = resultat_flood.group(3)
ip_dest = resultat_flood.group(4)
proto = int(protocole[resultat_flood.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_flood.group(6))
port_dest = int(resultat_flood.group(7))
# On remplit la base :
######################
date=strptime.syslog2pgsql(date)
except ValueError, KeyError:
continue
requete = "INSERT INTO flood (date,ip_src,ip_dest,id,port_src,port_dest) VALUES ('%s','%s','%s',%d,%d,%d)" % (date,ip_src,ip_dest,proto,port_src,port_dest)
curseur.execute(requete)

View file

@ -1,9 +1,9 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
"""DESCRIPTION """DESCRIPTION
Ce script repère les comptes inactifs en parsant les logs de dernière Ce script repère les comptes inactifs en parsant les logs de dernière
connexion de sshd et dovecot, et en lisant et mettant à jour les champs connexion de sshd et dovecot, et en lisant et mettant à jour les champs
derniereConnexion dans la base LDAP. derniereConnexion dans la base LDAP.
UTILISATION UTILISATION
@ -12,7 +12,7 @@ UTILISATION
ACTIONS POSSIBLES ACTIONS POSSIBLES
%(acts)s""" %(acts)s"""
# Copyright (C) 2006 Stéphane Glondu # Copyright (C) 2006 Stéphane Glondu
# Licence : GPLv2 # Licence : GPLv2
@ -41,8 +41,8 @@ openlog('comptes_inactifs')
def nb_mails_non_lus(login): def nb_mails_non_lus(login):
""" """
Renvoie le nombre de mails non lus de login, ou None si impossible à Renvoie le nombre de mails non lus de login, ou None si impossible à
déterminer. déterminer.
""" """
try: try:
maildir = '/var/mail/%s/new' % login maildir = '/var/mail/%s/new' % login
@ -56,8 +56,8 @@ def nb_mails_non_lus(login):
class ComptesInactifs(object): class ComptesInactifs(object):
# liste d'expressions régulières qui seront testées sur les lignes de log # liste d'expressions régulières qui seront testées sur les lignes de log
# le premier groupe doit correspondre à la date, le second au login # le premier groupe doit correspondre à la date, le second au login
re = [re.compile(r'^(\w+\s+\d+\s+\d+:\d+:\d+).*(?:' re = [re.compile(r'^(\w+\s+\d+\s+\d+:\d+:\d+).*(?:'
r'dovecot.*Login: user=<|' r'dovecot.*Login: user=<|'
r'sshd.*Accepted.*for ' r'sshd.*Accepted.*for '
@ -70,7 +70,7 @@ class ComptesInactifs(object):
self.dic = {} self.dic = {}
def search(self, query, mode=''): def search(self, query, mode=''):
""" CransLdap.search allégé """ """ CransLdap.search allégé """
query = '(&(objectClass=cransAccount)(objectClass=adherent)(%s))' % query query = '(&(objectClass=cransAccount)(objectClass=adherent)(%s))' % query
result = db.conn.search_s(db.base_dn, db.scope['adherent'], query) result = db.conn.search_s(db.base_dn, db.scope['adherent'], query)
result = [db.make(x, mode) for x in result] result = [db.make(x, mode) for x in result]
@ -79,13 +79,13 @@ class ComptesInactifs(object):
def commit_to_ldap(self): def commit_to_ldap(self):
""" """
Sauvegarde du dico dans la base LDAP. Sauvegarde du dico dans la base LDAP.
Renvoie le nombre d'entrées mises à jour. Renvoie le nombre d'entrées mises à jour.
""" """
total = 0 total = 0
for (login, timestamp) in self.dic.items(): for (login, timestamp) in self.dic.items():
a = self.search('uid=%s' % login, 'w') a = self.search('uid=%s' % login, 'w')
if not a: if not a:
# Probablement un adhérent récemment parti # Probablement un adhérent récemment parti
continue continue
a = a[0] a = a[0]
if a._modifiable == 'w': if a._modifiable == 'w':
@ -93,7 +93,7 @@ class ComptesInactifs(object):
if a.modifs: total += 1 if a.modifs: total += 1
a.save() a.save()
else: else:
# on loggue on espérant que les logs seront réinjectés # on loggue on espérant que les logs seront réinjectés
# plus tard # plus tard
syslog("LDAP(lock): derniereConnexion=<%s>, login=<%s>" % syslog("LDAP(lock): derniereConnexion=<%s>, login=<%s>" %
(strftime("%b %d %H:%M:%S", localtime(timestamp)), login)) (strftime("%b %d %H:%M:%S", localtime(timestamp)), login))
@ -101,7 +101,7 @@ class ComptesInactifs(object):
def update(self, login, timestamp): def update(self, login, timestamp):
""" """
Met à jour l'entrée correspondant au login donné. Met à jour l'entrée correspondant au login donné.
""" """
dic = self.dic dic = self.dic
timestamp = int(timestamp) timestamp = int(timestamp)
@ -110,8 +110,8 @@ class ComptesInactifs(object):
def update_from_syslog(self, loglines): def update_from_syslog(self, loglines):
""" """
Met à jour le dico avec les lignes de syslog données. Met à jour le dico avec les lignes de syslog données.
Renvoie le nombre de lignes traitées. Renvoie le nombre de lignes traitées.
""" """
annee = localtime(time())[0] annee = localtime(time())[0]
now = time() + 600 now = time() + 600
@ -124,8 +124,8 @@ class ComptesInactifs(object):
date = list(strptime(m.group(1), "%b %d %H:%M:%S")) date = list(strptime(m.group(1), "%b %d %H:%M:%S"))
date[0] = annee date[0] = annee
t = mktime(date) t = mktime(date)
# les lignes de syslog n'indiquent pas l'année # les lignes de syslog n'indiquent pas l'année
# on suppose qu'une date dans le futur est en fait l'année dernière # on suppose qu'une date dans le futur est en fait l'année dernière
if t > now: if t > now:
date[0] = annee - 1 date[0] = annee - 1
t = mktime(date) t = mktime(date)
@ -135,21 +135,21 @@ class ComptesInactifs(object):
def do_log(self): def do_log(self):
""" """
Lit des lignes de log sur l'entrée std et met à jour la base LDAP. Lit des lignes de log sur l'entrée std et met à jour la base LDAP.
""" """
parsed_lines = self.update_from_syslog(sys.stdin) parsed_lines = self.update_from_syslog(sys.stdin)
updated_entries = self.commit_to_ldap() updated_entries = self.commit_to_ldap()
syslog("%(parsed_lines)s ligne(s) traitée(s)" % locals()) syslog("%(parsed_lines)s ligne(s) traitée(s)" % locals())
syslog("%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP" % locals()) syslog("%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP" % locals())
if parsed_lines == 0 or updated_entries == 0: if parsed_lines == 0 or updated_entries == 0:
sys.stderr.write("""Erreur lors de la mise à jour de la base LDAP : sys.stderr.write("""Erreur lors de la mise à jour de la base LDAP :
%(parsed_lines)s ligne(s) traitée(s) %(parsed_lines)s ligne(s) traitée(s)
%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP %(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP
""" % locals()) """ % locals())
def do_dump(self): def do_dump(self):
""" """
Affiche la liste des dernières connexions, triées par date. Affiche la liste des dernières connexions, triées par date.
""" """
liste = self.search('derniereConnexion=*') liste = self.search('derniereConnexion=*')
liste = [(x.derniereConnexion(), x.compte()) for x in liste] liste = [(x.derniereConnexion(), x.compte()) for x in liste]
@ -157,15 +157,15 @@ class ComptesInactifs(object):
liste = [(x[1], strftime('%d/%m/%Y %H:%M', localtime(x[0]))) liste = [(x[1], strftime('%d/%m/%Y %H:%M', localtime(x[0])))
for x in liste] for x in liste]
cprint(tableau(liste, cprint(tableau(liste,
titre = (u'Login', u'Dernière connexion'), titre = (u'Login', u'Dernière connexion'),
largeur = (20, 20))) largeur = (20, 20)))
cprint(u"Total : %d" % len(liste)) cprint(u"Total : %d" % len(liste))
def get_idle_accounts(self, since=32*24*3600): def get_idle_accounts(self, since=32*24*3600):
""" """
Renvoie la liste des objets Adherent de ceux qui ne se sont pas Renvoie la liste des objets Adherent de ceux qui ne se sont pas
connectés depuis since secondes, par défaut un mois (32 jours, connectés depuis since secondes, par défaut un mois (32 jours,
pour être sûr). pour être sûr).
""" """
limit = int(time()) - since limit = int(time()) - since
liste = self.search("derniereConnexion<=%d" % limit) liste = self.search("derniereConnexion<=%d" % limit)
@ -176,20 +176,20 @@ class ComptesInactifs(object):
def do_summary(self): def do_summary(self):
""" """
Envoie à disconnect un résume des comptes inactifs depuis plus d'un Envoie à disconnect un résume des comptes inactifs depuis plus d'un
mois. mois.
""" """
modele = u"""*Membres inscrits ne s'étant pas connectés depuis plus d'un mois* modele = u"""*Membres inscrits ne s'étant pas connectés depuis plus d'un mois*
%(inscrits)s %(inscrits)s
Total : %(inscrits_total)d Total : %(inscrits_total)d
*Anciens membres ne s'étant pas connectés depuis plus d'un mois* *Anciens membres ne s'étant pas connectés depuis plus d'un mois*
%(anciens)s %(anciens)s
Total : %(anciens_total)d Total : %(anciens_total)d
Légende : Légende :
- F : existence d'un .forward - F : existence d'un .forward
- M : existence de mails non lus - M : existence de mails non lus
@ -219,7 +219,7 @@ comptes_inactifs.py
else: else:
anciens.append(ligne) anciens.append(ligne)
titres = (u'aid', u'Login', u'Nom', u'Dernière connexion', u'F', u'M') titres = (u'aid', u'Login', u'Nom', u'Dernière connexion', u'F', u'M')
largeurs = (6, 15, 20, 20, 1, 1) largeurs = (6, 15, 20, 20, 1, 1)
alignements = ('d', 'g', 'c', 'c', 'c', 'c') alignements = ('d', 'g', 'c', 'c', 'c', 'c')
@ -237,9 +237,9 @@ comptes_inactifs.py
def do_spam(self): def do_spam(self):
""" """
Envoie un mail explicatif aux possesseurs de compte inactif Envoie un mail explicatif aux possesseurs de compte inactif
(doit être exécuté en tant que root). (doit être exécuté en tant que root).
""" """
# Nombre de personnes concernées, en expansant de droite à gauche : # Nombre de personnes concernées, en expansant de droite à gauche :
# inscrit/ancien, avec/sans procmail, avec/sans mail non lu # inscrit/ancien, avec/sans procmail, avec/sans mail non lu
# Voir aussi template_path # Voir aussi template_path
stats = [0, 0, 0, 0, 0, 0, 0, 0] stats = [0, 0, 0, 0, 0, 0, 0, 0]
@ -262,7 +262,7 @@ comptes_inactifs.py
if not os.path.isfile('/home/%s/.forward' % login): i += 2 if not os.path.isfile('/home/%s/.forward' % login): i += 2
# a-il-des mails non lus ? # a-il-des mails non lus ?
if not mail: i += 1 if not mail: i += 1
# on incrémente # on incrémente
stats[i] += 1 stats[i] += 1
if i == 1: if i == 1:
# on laisse tranquilles les membres inscrits sans mails non # on laisse tranquilles les membres inscrits sans mails non
@ -303,7 +303,7 @@ comptes_inactifs.py
""" % total """ % total
send_email(mail_sender, send_email(mail_sender,
mail_report, mail_report,
u"Récapitulatif des comptes inactifs", u"Récapitulatif des comptes inactifs",
recapitulatif, recapitulatif,
server = smtp, server = smtp,
debug = debug) debug = debug)

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15 Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s, Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15 Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s, Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15 Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s, Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15 Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s, Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15 Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s, Bonjour %(nom)s,

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" """
Script de déconnection automatique des machines du crans pour les raisons : Script de déconnection automatique des machines du crans pour les raisons :

View file

@ -1,7 +1,7 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- encoding: iso-8859-15 -*- # -*- encoding: utf-8 -*-
# Utilisation de scappy pour détecter un DHCP pirate. # Utilisation de scappy pour détecter un DHCP pirate.
# $Id: dhcp-detect.py,v 1.3 2006/12/11 23:31:39 glondu Exp $ # $Id: dhcp-detect.py,v 1.3 2006/12/11 23:31:39 glondu Exp $
import sys, os import sys, os
@ -25,23 +25,23 @@ PIDFILE = "/var/run/dhcp-detect.pid"
# dhcp-server attendu # dhcp-server attendu
DHCPSERVER = '138.231.136.9' DHCPSERVER = '138.231.136.9'
# Interface à surveiller # Interface à surveiller
INTERFACE = "crans" INTERFACE = "crans"
# Adresse MAC # Adresse MAC
mac = os.popen(r"ifconfig | grep '^%s' | awk '{print $(NF)}'" % INTERFACE).readline().strip() mac = os.popen(r"ifconfig | grep '^%s' | awk '{print $(NF)}'" % INTERFACE).readline().strip()
# Paquet à envoyer pour détecter un DHCP (il a été capturé pour avoir la bonne tête) # Paquet à envoyer pour détecter un DHCP (il a été capturé pour avoir la bonne tête)
tosend = Ether("\xff\xff\xff\xff\xff\xff\x00\x80\xc8\xc9\xab\x01\x08\x00E\x10\x01H\x00\x00\x00\x00@\x11y\x96\x00\x00\x00\x00\xff\xff\xff\xff\x00D\x00C\x014\x9aA\x01\x01\x06\x00\xb2\x87\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xc8\xc9\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x82Sc5\x01\x012\x04R\xe1'67\x07\x01\x1c\x02\x03\x0f\x06\x0c\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") tosend = Ether("\xff\xff\xff\xff\xff\xff\x00\x80\xc8\xc9\xab\x01\x08\x00E\x10\x01H\x00\x00\x00\x00@\x11y\x96\x00\x00\x00\x00\xff\xff\xff\xff\x00D\x00C\x014\x9aA\x01\x01\x06\x00\xb2\x87\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xc8\xc9\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x82Sc5\x01\x012\x04R\xe1'67\x07\x01\x1c\x02\x03\x0f\x06\x0c\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
# On met à jour ce paquet # On met à jour ce paquet
tosend.getlayer(Ether).src = mac tosend.getlayer(Ether).src = mac
tosend.getlayer(IP).chksum = None tosend.getlayer(IP).chksum = None
tosend.getlayer(UDP).chksum = None tosend.getlayer(UDP).chksum = None
tosend.getlayer(BOOTP).chaddr = ''.join(map(lambda x: chr(int(x,16)),mac.split(":")+['0']*10)) tosend.getlayer(BOOTP).chaddr = ''.join(map(lambda x: chr(int(x,16)),mac.split(":")+['0']*10))
tosend = Ether(tosend.build()) tosend = Ether(tosend.build())
# Tableau associatif "mac" - "mailé pour la dernière fois" # Tableau associatif "mac" - "mailé pour la dernière fois"
dejavu = {} dejavu = {}
@ -88,7 +88,7 @@ def mail(paquet):
print "Envoi d'un mail...", print "Envoi d'un mail...",
msg = u"""Boujour, msg = u"""Boujour,
Un DHCP pirate a été découvert sur le réseau. Voici quelques renseignements mineurs à son sujet : Un DHCP pirate a été découvert sur le réseau. Voici quelques renseignements mineurs à son sujet :
Son adresse Ethernet : %s Son adresse Ethernet : %s
Son adresse IP : %s Son adresse IP : %s
@ -99,7 +99,7 @@ Un DHCP pirate a
msg += u"\n" msg += u"\n"
msg += info_machine(mac_pirate) msg += info_machine(mac_pirate)
msg += u""" msg += u"""
Merci de votre attention et à bientôt. Merci de votre attention et à bientôt.
-- --
dhcp-detect.py dhcp-detect.py
@ -111,10 +111,10 @@ dhcp-detect.py
print "ok" print "ok"
# Réception d'une réponse # Réception d'une réponse
def recoit(paquet): def recoit(paquet):
# On affiche # On affiche
print "Réception de : ", paquet.summary() print "Réception de : ", paquet.summary()
# On verifie que c'est bien ce qu'on attend # On verifie que c'est bien ce qu'on attend
if paquet.getlayer(Ether).dst.upper() == globals()['mac'] and paquet.haslayer(BOOTP) and paquet.getlayer(BOOTP).op == 2 and paquet.getlayer(IP).src != DHCPSERVER: if paquet.getlayer(Ether).dst.upper() == globals()['mac'] and paquet.haslayer(BOOTP) and paquet.getlayer(BOOTP).op == 2 and paquet.getlayer(IP).src != DHCPSERVER:
# DHCP pirate ? # DHCP pirate ?
@ -140,7 +140,7 @@ def get():
if __name__ == "__main__": if __name__ == "__main__":
# On quitte les éventuelles instances démonisées en cours # On quitte les éventuelles instances démonisées en cours
try: try:
pid = int(file(PIDFILE).read().strip()) pid = int(file(PIDFILE).read().strip())
os.kill(pid, 15) os.kill(pid, 15)
@ -150,12 +150,12 @@ if __name__ == "__main__":
createDaemon() createDaemon()
file(PIDFILE, "w").write("%d\n" % os.getpid()) file(PIDFILE, "w").write("%d\n" % os.getpid())
else: else:
print "Le paquet suivant va être envoyé à intervalles réguliers pour tester la présence de DHCP pirates :" print "Le paquet suivant va être envoyé à intervalles réguliers pour tester la présence de DHCP pirates :"
print tosend.summary() print tosend.summary()
openlog("dhcp-detect", LOG_PID) openlog("dhcp-detect", LOG_PID)
syslog("Démarrage de dhcp-detect") syslog("Démarrage de dhcp-detect")
# On démarre le thread qui envoie régulièrement le paquet... # On démarre le thread qui envoie régulièrement le paquet...
Thread(target=send, name="send").start() Thread(target=send, name="send").start()
# ...et celui qui sniffe régulièrement la réponse # ...et celui qui sniffe régulièrement la réponse
Thread(target=get, name="get").start() Thread(target=get, name="get").start()

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- encoding: iso-8859-15 -*- # -*- encoding: utf-8 -*-
########################### ###########################
@ -17,21 +17,21 @@ import re
sys.path.append('/usr/script/surveillance') sys.path.append('/usr/script/surveillance')
import strptime import strptime
# Définition de constantes : # Définition de constantes :
############################ ############################
reseau = ["138.231.136.0/21", "138.231.148.0/22"] reseau = ["138.231.136.0/21", "138.231.148.0/22"]
# Ouverture de la base de données : # Ouverture de la base de données :
################################### ###################################
pgsql = psycopg2.connect(host='pgsql.adm.crans.org', database='filtrage', user='crans') pgsql = psycopg2.connect(host='pgsql.adm.crans.org', database='filtrage', user='crans')
# Ancienne méthode pour faire de l'autocommit. # Ancienne méthode pour faire de l'autocommit.
# Sous wheezy, il faudra remplacer par pgsql.set_session(autocommit=True) !!! # Sous wheezy, il faudra remplacer par pgsql.set_session(autocommit=True) !!!
pgsql.set_isolation_level(0) pgsql.set_isolation_level(0)
curseur = pgsql.cursor() curseur = pgsql.cursor()
########################################### ###########################################
# Récupération des tables de protocoles : # # Récupération des tables de protocoles : #
########################################### ###########################################
requete = "SELECT nom,id_p2p from protocole_p2p" requete = "SELECT nom,id_p2p from protocole_p2p"
@ -56,7 +56,7 @@ for cellule in tableau:
# Parser ler log du firewall: /var/log/firewall/filtre.log : # # Parser ler log du firewall: /var/log/firewall/filtre.log : #
############################################################## ##############################################################
# Définition des motifs des comparaisons : # Définition des motifs des comparaisons :
########################################## ##########################################
motif_p2p = re.compile("^(.*) komaz .* IPP2P=([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*") motif_p2p = re.compile("^(.*) komaz .* IPP2P=([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
@ -65,7 +65,7 @@ motif_virus = re.compile("^(.*) komaz .* Virus:([^ ]*).* SRC=([^ ]*).* DST=([^ ]
motif_flood = re.compile("^(.*) komaz .* Flood:([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*") motif_flood = re.compile("^(.*) komaz .* Flood:([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
# On récupère en continu les log du firewall: # On récupère en continu les log du firewall:
############################################# #############################################
filtre = os.popen("tail -F /var/log/firewall/filtre.log 2> /dev/null") filtre = os.popen("tail -F /var/log/firewall/filtre.log 2> /dev/null")
@ -89,7 +89,7 @@ for log in filtre:
id_p2p = int(protocole_p2p[resultat_p2p.group(2)]) id_p2p = int(protocole_p2p[resultat_p2p.group(2)])
ip_src = resultat_p2p.group(3) ip_src = resultat_p2p.group(3)
ip_dest = resultat_p2p.group(4) ip_dest = resultat_p2p.group(4)
proto = int(protocole[resultat_p2p.group(5)]) #C'est à dire id pour la base proto = int(protocole[resultat_p2p.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_p2p.group(6)) port_src = int(resultat_p2p.group(6))
port_dest = int(resultat_p2p.group(7)) port_dest = int(resultat_p2p.group(7))
date=strptime.syslog2pgsql(date) date=strptime.syslog2pgsql(date)
@ -114,7 +114,7 @@ for log in filtre:
date = resultat_virus.group(1) date = resultat_virus.group(1)
ip_src = resultat_virus.group(3) ip_src = resultat_virus.group(3)
ip_dest = resultat_virus.group(4) ip_dest = resultat_virus.group(4)
proto = int(protocole[resultat_virus.group(5)]) #C'est à dire id pour la base proto = int(protocole[resultat_virus.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_virus.group(6)) port_src = int(resultat_virus.group(6))
port_dest = int(resultat_virus.group(7)) port_dest = int(resultat_virus.group(7))
# On remplit la base : # On remplit la base :
@ -136,7 +136,7 @@ for log in filtre:
date = resultat_flood.group(1) date = resultat_flood.group(1)
ip_src = resultat_flood.group(3) ip_src = resultat_flood.group(3)
ip_dest = resultat_flood.group(4) ip_dest = resultat_flood.group(4)
proto = int(protocole[resultat_flood.group(5)]) #C'est à dire id pour la base proto = int(protocole[resultat_flood.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_flood.group(6)) port_src = int(resultat_flood.group(6))
port_dest = int(resultat_flood.group(7)) port_dest = int(resultat_flood.group(7))

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
########################### ###########################
# Import des commmandes : # # Import des commmandes : #

View file

@ -1,13 +1,13 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
############################################################################### ###############################################################################
# parse_auth_log.py : Détecte les problèmes d'authentifications # parse_auth_log.py : Détecte les problèmes d'authentifications
############################################################################### ###############################################################################
# The authors of this code are # The authors of this code are
# Jérémie Dimino <dimino@crans.org> # Jérémie Dimino <dimino@crans.org>
# #
# Copyright (C) 2006 Jérémie Dimino # Copyright (C) 2006 Jérémie Dimino
# All rights reserved. # All rights reserved.
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
@ -40,7 +40,7 @@ prise_chbre = {}
aujourdhui = datetime.date.today() aujourdhui = datetime.date.today()
def trouve_chambre(bat, prise): def trouve_chambre(bat, prise):
""" Trouve la chambre associée à une prise """ """ Trouve la chambre associée à une prise """
if prise in ('????', 'EXT', 'CRA'): if prise in ('????', 'EXT', 'CRA'):
return prise return prise
@ -59,7 +59,7 @@ def trouve_chambre(bat, prise):
def trouve_prise(chbre): def trouve_prise(chbre):
""" Trouve la prise associée à une chambre """ """ Trouve la prise associée à une chambre """
if chbre in ('EXT', '????', 'CRA'): if chbre in ('EXT', '????', 'CRA'):
return chbre return chbre
@ -72,7 +72,7 @@ def trouve_prise(chbre):
def __calcul_max(table): def __calcul_max(table):
""" Calcule les différents maxima (voir parse_auth_log pour plus de détails) """ """ Calcule les différents maxima (voir parse_auth_log pour plus de détails) """
nb_m = 0 nb_m = 0
nb_p = 0 nb_p = 0
@ -93,7 +93,7 @@ def __calcul_max(table):
def __ajoute_ligne(errs, ligne, prise, mac, info=None): def __ajoute_ligne(errs, ligne, prise, mac, info=None):
""" Ajoute une ligne dans le dico pour la prise et la mac donnée """ """ Ajoute une ligne dans le dico pour la prise et la mac donnée """
erreur_prise = errs.get(prise) erreur_prise = errs.get(prise)
if not erreur_prise: if not erreur_prise:
@ -108,29 +108,29 @@ def __ajoute_ligne(errs, ligne, prise, mac, info=None):
erreur_mac['lignes'].append(ligne) erreur_mac['lignes'].append(ligne)
# Correspondance 'noms de mois' -> n° # Correspondance 'noms de mois' -> n°
__mois_num = { 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, __mois_num = { 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 } 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 }
def parse_auth_log(fichier_log='/var/log/freeradius/radius_auth.log', jour=None): def parse_auth_log(fichier_log='/var/log/freeradius/radius_auth.log', jour=None):
""" Retourne la liste des problèmes de connexions: retourne deux dicos, la première étant pour les macs qui n'ont pas été trouvées dans la base et la seconde pour les connexions qui ont eu lieu à partir d'une mauvaise prise """ Retourne la liste des problèmes de connexions: retourne deux dicos, la première étant pour les macs qui n'ont pas été trouvées dans la base et la seconde pour les connexions qui ont eu lieu à partir d'une mauvaise prise
les deux dictionnaires ont la structure suivante: les deux dictionnaires ont la structure suivante:
- nombre_mac_max: nombre maximal d'erreurs trouvées pour une mac - nombre_mac_max: nombre maximal d'erreurs trouvées pour une mac
- nombre_prise_max: nombre maximal d'erreurs trouvées pour une prise - nombre_prise_max: nombre maximal d'erreurs trouvées pour une prise
- prises: dico associant à une prise la listes des erreurs à partir de cette prise: - prises: dico associant à une prise la listes des erreurs à partir de cette prise:
- nombre: nombre total d'erreurs survenues sur la prise - nombre: nombre total d'erreurs survenues sur la prise
- nombre_max: nombre maximal d'erreurs trouvéss pour une mac - nombre_max: nombre maximal d'erreurs trouvéss pour une mac
- macs: dico associant à une mac la liste des erreurs à partir de cette mac - macs: dico associant à une mac la liste des erreurs à partir de cette mac
- nombre: le nombre d'erreurs survenues pour cette mac sur cette prise - nombre: le nombre d'erreurs survenues pour cette mac sur cette prise
- lignes: la liste des lignes du fichier de logs la mac apparaît sur cette prise - lignes: la liste des lignes du fichier de logs la mac apparaît sur cette prise
- info: informations sur le propriétaire (vaut None pour la première table) - info: informations sur le propriétaire (vaut None pour la première table)
- machine: la machine en question - machine: la machine en question
- prise: la prise de sa chambre - prise: la prise de sa chambre
- chambre: sa chambre - chambre: sa chambre
- prop: le propriétaire - prop: le propriétaire
Si jour est spécifié (de type datetime.date), toutes les connexions avant cette dates seront ignorées. Si jour est spécifié (de type datetime.date), toutes les connexions avant cette dates seront ignorées.
""" """
try: try:
@ -139,13 +139,13 @@ Si jour est sp
cprint(u"Impossible d'ouvrir le fichier %s" % fichier_log, 'rouge') cprint(u"Impossible d'ouvrir le fichier %s" % fichier_log, 'rouge')
sys.exit(1) sys.exit(1)
# Les macs non trouvées # Les macs non trouvées
errs_inconnue = {} errs_inconnue = {}
# Les pc connectés sur la mauvaise prise # Les pc connectés sur la mauvaise prise
errs_prise = {} errs_prise = {}
# Les recherches déjà effectuées sur les macs # Les recherches déjà effectuées sur les macs
mac_machine = {} mac_machine = {}
annee = None annee = None
@ -161,12 +161,12 @@ Si jour est sp
if annee == None: if annee == None:
if nouveau_mois > aujourdhui.month: if nouveau_mois > aujourdhui.month:
# Là on suppose qu'il s'agit de l'année dernière # Là on suppose qu'il s'agit de l'année dernière
annee = aujourdhui.year - 1 annee = aujourdhui.year - 1
else: else:
annee = aujourdhui.year annee = aujourdhui.year
elif mois > nouveau_mois: elif mois > nouveau_mois:
# Là on suppose qu'on est passé à l'année suivante # Là on suppose qu'on est passé à l'année suivante
annee += 1 annee += 1
mois = nouveau_mois mois = nouveau_mois
@ -213,7 +213,7 @@ Si jour est sp
def affiche_erreurs(errs, message, min_mac=1, min_prise=1): def affiche_erreurs(errs, message, min_mac=1, min_prise=1):
""" Affiche les infos contenues dans un dico renvoyé par parse_auth_log """ """ Affiche les infos contenues dans un dico renvoyé par parse_auth_log """
if errs['nombre_mac_max'] >= min_mac and errs['nombre_prise_max'] >= min_prise: if errs['nombre_mac_max'] >= min_mac and errs['nombre_prise_max'] >= min_prise:
@ -248,35 +248,35 @@ def __usage(err=''):
def __param_entier(opt, val): def __param_entier(opt, val):
""" Récupère un entier passé en ligne de commande """ """ Récupère un entier passé en ligne de commande """
try: try:
return int(val) return int(val)
except: except:
__usage(u'La valeur du paramètre %s est incorecte (doit être un entier positif)' % opt) __usage(u'La valeur du paramètre %s est incorecte (doit être un entier positif)' % opt)
def __aide(): def __aide():
""" Aide """ """ Aide """
cprint(u"""Usage: %s [OPTIONS] cprint(u"""Usage: %s [OPTIONS]
Parse les logs d'authentifications et affiche les erreurs trouvées (macs inconnues ou connexion d'une machine sur une prise autre que celle du propriétaire). Parse les logs d'authentifications et affiche les erreurs trouvées (macs inconnues ou connexion d'une machine sur une prise autre que celle du propriétaire).
Options: Options:
-h, --help affiche cette aide -h, --help affiche cette aide
-l, --log <fichier> fichier de log à parser (par défaut: /var/log/freeradius/radius_auth.log) -l, --log <fichier> fichier de log à parser (par défaut: /var/log/freeradius/radius_auth.log)
-m, --min-mac <nombre> nombre minimal d'occurrences d'une mac sur une prise pour qu'elle soit reportée -m, --min-mac <nombre> nombre minimal d'occurrences d'une mac sur une prise pour qu'elle soit reportée
-n, --min-prise <nombre> nombre minimal d'erreurs sur une prise pour qu'elle soit reportée -n, --min-prise <nombre> nombre minimal d'erreurs sur une prise pour qu'elle soit reportée
-i, --inconnue n'affiche que les erreurs de mac inconnues -i, --inconnue n'affiche que les erreurs de mac inconnues
-p, --prise n'affiche que les connexions sur une prise autre que celle du propriétaire -p, --prise n'affiche que les connexions sur une prise autre que celle du propriétaire
-d, --date <date> ignorer totalement les lignes avant cette date -d, --date <date> ignorer totalement les lignes avant cette date
<date> peut être: <date> peut être:
- une date absolue sous la forme AAAAMMJJ - une date absolue sous la forme AAAAMMJJ
- une date relative à aujourd'hui sous la forme +<nombre de jour> - une date relative à aujourd'hui sous la forme +<nombre de jour>
Par exemple pour ne considérer que les deux dernier jours: +2 Par exemple pour ne considérer que les deux dernier jours: +2
Rapporter toutes anomalies à <dimino@crans.org>.""" % sys.argv[0].split('/')[-1].split('.')[0]) Rapporter toutes anomalies à <dimino@crans.org>.""" % sys.argv[0].split('/')[-1].split('.')[0])
sys.exit(0) sys.exit(0)
@ -288,7 +288,7 @@ if __name__ == '__main__':
# Info que l'on veut afficher # Info que l'on veut afficher
aff_inconnue = True aff_inconnue = True
aff_prise = True aff_prise = True
# Date de départ # Date de départ
jour = None jour = None
import getopt, time import getopt, time
@ -318,7 +318,7 @@ if __name__ == '__main__':
try: try:
jour = datetime.date(*(time.strptime(val, "%Y%m%d")[0:3])) jour = datetime.date(*(time.strptime(val, "%Y%m%d")[0:3]))
except: except:
__usage(u'La valeur du paramètre %s est incorecte (doit être de la forme AAAAMMJJ)' % opt) __usage(u'La valeur du paramètre %s est incorecte (doit être de la forme AAAAMMJJ)' % opt)
else: else:
cprint(u'Option inconnue: %s' % opt, 'rouge') cprint(u'Option inconnue: %s' % opt, 'rouge')
__usage() __usage()
@ -328,7 +328,7 @@ if __name__ == '__main__':
errs_inconnue, errs_prise = parse_auth_log(fichier_log, jour) errs_inconnue, errs_prise = parse_auth_log(fichier_log, jour)
if aff_inconnue: if aff_inconnue:
affiche_erreurs(errs_inconnue, u"Pour les connexions suivantes la mac n'a pas été trouvée dans la base:", min_mac, min_prise) affiche_erreurs(errs_inconnue, u"Pour les connexions suivantes la mac n'a pas été trouvée dans la base:", min_mac, min_prise)
if aff_prise: if aff_prise:
affiche_erreurs(errs_prise, u"Les connexions suivantes ont eu lieu sur une prise autre que celle du proriétaire:", min_mac, min_prise) affiche_erreurs(errs_prise, u"Les connexions suivantes ont eu lieu sur une prise autre que celle du proriétaire:", min_mac, min_prise)

View file

@ -1,11 +1,11 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- encoding: iso-8859-15 -*- # -*- encoding: utf-8 -*-
""" """
Script d'envoi des statistiques des déconnections Script d'envoi des statistiques des déconnections
et du trafic de la journée à disconnect@ et du trafic de la journée à disconnect@
Copyright (C) Xavier Pessoles - Étienne Chové - Michel Blockelet Copyright (C) Xavier Pessoles - Étienne Chové - Michel Blockelet
Licence : GPLv2 Licence : GPLv2
""" """
@ -111,9 +111,9 @@ liste_upload = tableau(data = [ (l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn(
titre = ['upload', 'download', 'proto', 'machine'], titre = ['upload', 'download', 'proto', 'machine'],
largeur = [10, 10, 10, 40], largeur = [10, 10, 10, 40],
format = ['o', 'o', 's', 's'], format = ['o', 'o', 's', 's'],
alignement = ['d', 'd', 'c', 'c']).encode('iso-8859-15') alignement = ['d', 'd', 'c', 'c']).encode('utf-8')
# Trafic exempté : # Trafic exempté :
################## ##################
requete = """(SELECT ip_crans, sum(upload) AS somme, sum(download) requete = """(SELECT ip_crans, sum(upload) AS somme, sum(download)
FROM upload FROM upload
@ -149,7 +149,7 @@ liste_exemptes = tableau(data = [[l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn
titre = ['upload', 'download', 'proto', 'machine'], titre = ['upload', 'download', 'proto', 'machine'],
largeur = [10, 10, 10, 30], largeur = [10, 10, 10, 30],
format = ['o', 'o', 's', 's'], format = ['o', 'o', 's', 's'],
alignement = ['d', 'd', 'c', 'c']).encode('iso-8859-15') alignement = ['d', 'd', 'c', 'c']).encode('utf-8')
# Upload des serveurs : # Upload des serveurs :
####################### #######################
@ -170,7 +170,7 @@ liste_serveurs = tableau(data = liste_serveurs,
titre = ['upload', 'download', 'proto', 'serveur'], titre = ['upload', 'download', 'proto', 'serveur'],
largeur = [10, 10, 10, 30], largeur = [10, 10, 10, 30],
format = ['o', 'o', 's', 's'], format = ['o', 'o', 's', 's'],
alignement = ['d', 'd', 'c', 'c']).encode('iso-8859-15') alignement = ['d', 'd', 'c', 'c']).encode('utf-8')
# statistiques des gros uploads depuis les serveurs # statistiques des gros uploads depuis les serveurs
@ -178,7 +178,7 @@ liste_serveurs = tableau(data = liste_serveurs,
# Liste des IP des serveurs # Liste des IP des serveurs
gros_uploads_des_serveurs = stats(ip_crans=ips_serveurs, gros_uploads_des_serveurs = stats(ip_crans=ips_serveurs,
show=['ip_crans', 'ip_ext'], upload_mini=50, show=['ip_crans', 'ip_ext'], upload_mini=50,
show_limit=100).encode('iso-8859-15') show_limit=100).encode('utf-8')
############################ ############################
# Statistiques virus/p2p : # # Statistiques virus/p2p : #
@ -206,10 +206,10 @@ liste_etherunk = tableau(data = [[l[0], socket.getfqdn(str(l[1]))]
for l in curseur.fetchall()], for l in curseur.fetchall()],
titre = ['nombre','ip'], titre = ['nombre','ip'],
largeur = [10, 30], largeur = [10, 30],
alignement = ['d','c']).encode('iso-8859-15') alignement = ['d','c']).encode('utf-8')
# Machines actuellement déconnectées : # Machines actuellement déconnectées :
###################################### ######################################
requete = "SELECT DISTINCT ip_crans FROM avertis_virus" requete = "SELECT DISTINCT ip_crans FROM avertis_virus"
curseur.execute(requete) curseur.execute(requete)
@ -220,9 +220,9 @@ for IP in infections:
liste_virus.append(["%s" % (str(hostname))]) liste_virus.append(["%s" % (str(hostname))])
liste_virus = tableau(liste_virus, liste_virus = tableau(liste_virus,
titre=['machine'], largeur=[30]).encode('iso-8859-15') titre=['machine'], largeur=[30]).encode('utf-8')
# Machines ayant fait des attaques virus dans la journée : # Machines ayant fait des attaques virus dans la journée :
########################################################## ##########################################################
requete = """SELECT * FROM (SELECT ip_src,count(ip_src) as compteur FROM virus requete = """SELECT * FROM (SELECT ip_src,count(ip_src) as compteur FROM virus
WHERE date > timestamp 'now' - interval '1 day' WHERE date > timestamp 'now' - interval '1 day'
@ -237,10 +237,10 @@ for IP, compteur in curseur.fetchall():
liste_virus2 = tableau(data = liste_virus2, liste_virus2 = tableau(data = liste_virus2,
titre = ['machine', 'nombre'], titre = ['machine', 'nombre'],
largeur = [30, 12], largeur = [30, 12],
alignement = ['c', 'd']).encode('iso-8859-15') alignement = ['c', 'd']).encode('utf-8')
# Machines ayant fait de attaques flood dans la journée : # Machines ayant fait de attaques flood dans la journée :
######################################################### #########################################################
requete = """SELECT * FROM (SELECT ip_src,count(ip_src) as compteur FROM flood requete = """SELECT * FROM (SELECT ip_src,count(ip_src) as compteur FROM flood
WHERE date > timestamp 'now' - interval '1 day' WHERE date > timestamp 'now' - interval '1 day'
@ -255,7 +255,7 @@ for IP, compteur in curseur.fetchall():
liste_virus3 = tableau(data = liste_virus3, liste_virus3 = tableau(data = liste_virus3,
titre = ['machine', 'nombre'], titre = ['machine', 'nombre'],
largeur = [30, 12], largeur = [30, 12],
alignement = ['c', 'd']).encode('iso-8859-15') alignement = ['c', 'd']).encode('utf-8')
############# #############
@ -266,11 +266,11 @@ expediteur = "disconnect@crans.org"
destinataire = "disconnect@crans.org" destinataire = "disconnect@crans.org"
message = """From: %(From)s message = """From: %(From)s
To: %(To)s To: %(To)s
Subject: Statistiques des =?iso-8859-1?Q?derni=E8res?= 24h Subject: Statistiques des =?utf-8?q?derni=C3=A8res?= 24h
Message-Id: <%(uuid)s1@crans.org> Message-Id: <%(uuid)s1@crans.org>
Content-Type: text/plain; charset="iso-8859-15" Content-Type: text/plain; charset="utf-8"
*Gros uploads des serveurs* (charybde et sable sont exemptés totalement) *Gros uploads des serveurs* (charybde et sable sont exemptés totalement)
%(gros_uploads_des_serveurs)s %(gros_uploads_des_serveurs)s
@ -282,23 +282,23 @@ Content-Type: text/plain; charset="iso-8859-15"
%(liste_etherunk)s %(liste_etherunk)s
*Machines actuellement déconnectées pour virus* *Machines actuellement déconnectées pour virus*
%(liste_virus)s %(liste_virus)s
*Machines ayant commis des attaques virales dans la journée* *Machines ayant commis des attaques virales dans la journée*
%(liste_virus2)s %(liste_virus2)s
*Machines ayant commis des attaques virales de type flood dans la journée* *Machines ayant commis des attaques virales de type flood dans la journée*
%(liste_virus3)s %(liste_virus3)s
*Statistiques de trafic des adhérents* (tout le trafic) *Statistiques de trafic des adhérents* (tout le trafic)
%(liste_upload)s %(liste_upload)s
*Statistiques de trafic des adhérents exemptés* (juste le trafic exempté) *Statistiques de trafic des adhérents exemptés* (juste le trafic exempté)
%(liste_exemptes)s %(liste_exemptes)s

View file

@ -1,12 +1,12 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
"""chambre_on_off.py: Affiche le statut, active ou désactive une prise """chambre_on_off.py: Affiche le statut, active ou désactive une prise
syntaxe : chambre-on-off.py chbre <cmd> syntaxe : chambre-on-off.py chbre <cmd>
chbre de la forme A101d chbre de la forme A101d
<cmd> peut être : <cmd> peut être :
- on : activer la prise - on : activer la prise
- off : désactiver la prise - off : désactiver la prise
- absent : affiche le statut de la prise - absent : affiche le statut de la prise
""" """
@ -17,10 +17,10 @@ sys.path.append("/usr/scripts/gestion/")
import hptools import hptools
def chambre_on_off(chambre, cmd = None): def chambre_on_off(chambre, cmd = None):
"""Active ou désactive une prise """Active ou désactive une prise
chambre: numéro de chambre chambre: numéro de chambre
cmd: si fourni, "on" ou "off" pour activer ou désactiver la prise cmd: si fourni, "on" ou "off" pour activer ou désactiver la prise
si cmd n'est pas fourni, ne fait qu'afficher le statut de la prise si cmd n'est pas fourni, ne fait qu'afficher le statut de la prise
""" """
# connexion au switch # connexion au switch