[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
# -*- 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
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.
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.
Utilisation :
%(prog)s {liste|modif|spam} [--debug <adresse>]
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
Les commandes sont :
* liste énumérer les membres n'ayant pas signé la charte
* modif modifier les membres actifs 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
* 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
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
db = crans_ldap()
@ -44,12 +44,12 @@ if __name__ == '__main__':
sys.argv.pop()
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):
"""
Contrôle interactif des adhérents de la liste.
Contrôle interactif des adhérents de la liste.
Retourne (nb_OK, nb_pas_OK).
"""
@ -57,10 +57,10 @@ def _controle_interactif_adherents(liste):
if restant == 0:
return 0, 0
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"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
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"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
cprint(u"")
nb = 0
@ -81,7 +81,7 @@ def _controle_interactif_adherents(liste):
modifiable.charteMA(True)
cprint(modifiable.save())
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':
if a.charteMA() == True:
modifiable = db.search('aid=%s' % a.id(), 'w')['adherent'][0]
@ -89,16 +89,16 @@ def _controle_interactif_adherents(liste):
modifiable.charteMA(False)
cprint(modifiable.save())
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:
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
return nb, len(liste)-nb
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_nok = []
for adh in liste_actifs:
@ -110,25 +110,25 @@ def liste_charte_nok():
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()
# 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
# 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
todo_list.sort(lambda x, y: cmp((x.nom(), x.prenom()), (y.nom(), y.prenom())))
# Zou !
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)]]
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]))
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()
if todo_list:
@ -144,10 +144,10 @@ def spammer():
print to
if not debug:
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):
""" Comment ça marche ? """
""" Comment ça marche ? """
cprint(__doc__ % { 'prog': sys.argv[0] })
if message:
cprint(message)
@ -161,7 +161,7 @@ if __name__ == '__main__' :
elif sys.argv[1] == 'liste':
if len(sys.argv) != 2:
__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():
print adh.Nom()
elif sys.argv[1] == 'modif':

View file

@ -1,43 +1,43 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
# Copyright (C) Stéphane Glondu
# Copyright (C) Stéphane Glondu
# Licence : GPLv2
u"""Ce script permet au trésorier de repérer plus facilement les papiers que
les câbleurs n'ont pas encore rendus.
u"""Ce script permet au trésorier de repérer plus facilement les papiers que
les câbleurs n'ont pas encore rendus.
Utilisations possibles :
* %(prog)s OPTIONS {paiement|carte|list}
* %(prog)s OPTIONS mail <liste>
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
-h, --help affiche ce message
-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
Les commandes sont :
* paiement contrôle interactif des nouvelles (-)adhésions
* carte contrôle interactif des nouvelles cartes d'étudiant
* list affiche le récapitulatif des papiers manquants
* mail <liste> envoyer les mails de rappel aux câbleurs dont le
login est dans la <liste>, 'bureau' désignant le mail
récapitulatif envoyé à bureau ; si la liste est vide
tous les mails nécessaires seront envoyés
* paiement contrôle interactif des nouvelles (-)adhésions
* carte contrôle interactif des nouvelles cartes d'étudiant
* list affiche le récapitulatif des papiers manquants
* mail <liste> envoyer les mails de rappel aux câbleurs dont le
login est dans la <liste>, 'bureau' désignant le mail
récapitulatif envoyé à bureau ; si la liste est vide
tous les mails nécessaires seront envoyés
* help affiche ce message
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 :
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 :
Encoding: <encodage du fichier>
Subject: <sujet du mail>
<ligne vide>
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
@ -46,21 +46,21 @@ sys.path.append('/usr/scripts/gestion')
# Fonctions d'affichage
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
db = crans_ldap()
# Détermination de l'uid du câbleur
# Détermination de l'uid du câbleur
from user_tests import getuser
uid = getuser()
if not uid :
cprint(u"Impossible de déterminer l'utilisateur !")
cprint(u"Impossible de déterminer l'utilisateur !")
sys.exit(1)
cableur = db.search('uid=%s' % uid)['adherent'][0]
# Vérification des droits
# Vérification des 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)
# Lors des tests, on m'envoie tous les mails !
@ -77,19 +77,19 @@ if gethostname().split(".")[0] == 'egon':
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).
"""
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)
if restant == 0:
return 0, 0
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"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
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"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
cprint(u"")
nb = 0
@ -104,9 +104,9 @@ def _controle_interactif_adherents(liste, quoi):
cprint(modifiable.save())
nb += 1
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':
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
return nb, len(liste)-nb
@ -114,16 +114,16 @@ def _controle_interactif_adherents(liste, quoi):
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).
"""
restant = len(liste)
if restant == 0:
return 0, 0
cprint(u'\nContrôle de la charte des clubs', 'cyan')
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'\nContrôle de la charte des clubs', 'cyan')
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"Le format est [nb_restant] Nom (cid).")
cprint(u"")
@ -139,17 +139,17 @@ def _controle_interactif_clubs(liste):
cprint(modifiable.save())
nb += 1
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':
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
return nb, len(liste)-nb
def qui(historique, quoi):
"""
Recherche le câbleur qui a effectué la dernière modification quoi
dans l'historique, ou qui a inscrit l'adhérent.
Recherche le câbleur qui a effectué la dernière modification quoi
dans l'historique, ou qui a inscrit l'adhérent.
Retourne le couple (date, cableur) ou ('_inconnu_', '_inconnu_').
"""
regexp = re.compile(r'^([^,]*), ([^ :]*)')
@ -166,13 +166,13 @@ def qui(historique, 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
todo_list = db.search('%s=%d&controle!=*%s*'
% ({'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()))
if trier_par == 'id':
@ -183,7 +183,7 @@ def controle_interactif(quoi):
champ = { 'date': 0, 'cableur': 1 }[trier_par]
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)
if quoi == 'p':
@ -193,18 +193,18 @@ def controle_interactif(quoi):
# Traitement des clubs (uniquement la charte)
okc, nokc =_controle_interactif_clubs(todo_list['club'])
cprint(u'\nRécapitulatif des nouveaux contrôles +%s :' % quoi, 'violet')
liste = [[u'adhérents', str(oka), str(noka)]]
cprint(u'\nRécapitulatif des nouveaux contrôles +%s :' % quoi, 'violet')
liste = [[u'adhérents', str(oka), str(noka)]]
if quoi == 'p':
liste.append([u'clubs', str(okc), str(nokc)])
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]))
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).
"""
lignes = []
@ -231,8 +231,8 @@ def formater_pour_cableur(liste):
def formater_pour_bureau(dico):
"""
Formate la liste d'adhérents ou de clubs avec les câbleurs correspondantes
pour le mail récapitulatif envoyé à bureau.
Formate la liste d'adhérents ou de clubs avec les câbleurs correspondantes
pour le mail récapitulatif envoyé à bureau.
"""
lignes = []
total = 0
@ -253,15 +253,15 @@ def formater_pour_bureau(dico):
if tri_inverse: lignes.reverse()
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],
alignement = ['d', 'c', 'c', 'c']) + u'\nTotal : %d' % total
def chercher_cableurs(liste, quoi):
"""
Renvoie un dictionnaire cableur->adherents à partir de liste, quoi
désigne le champ qui sera recherché dans l'historique.
Renvoie un dictionnaire cableur->adherents à partir de liste, quoi
désigne le champ qui sera recherché dans l'historique.
"""
resultat = {}
@ -275,21 +275,21 @@ def chercher_cableurs(liste, quoi):
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:
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)
self._paiements = chercher_cableurs(todo_list['adherent'], r'(paiement|controle.*\+k)')
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)
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 = {}
for a in self._paiements.keys():
if a != '_inconnu_': cableurs[a] = None
@ -299,14 +299,14 @@ class ControleMailer:
if a != '_inconnu_': cableurs[a] = None
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():
self._sender = u'%s <tresorier@crans.org>' % cableur.Nom()
else:
self._sender = u'%s <%s@crans.org>' % (cableur.Nom(),
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
self._server = SMTP()
self._server.connect()
@ -317,47 +317,47 @@ class ControleMailer:
def recapitulatif(self):
"""
Renvoie le récapitulatif pour le bureau.
Renvoie le récapitulatif pour le bureau.
"""
msg = u''
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'
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'
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'
return msg.strip()
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()
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,
u"Bureau <bureau@crans.org>",
u"Récapitulatif des papiers manquants",
u"Récapitulatif des papiers manquants",
msg,
server = self._server,
debug = debug)
return coul(u'Mail envoyé à bureau avec succès !', 'vert')
return coul(u'Mail envoyé à bureau avec succès !', 'vert')
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):
"""
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.
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.
Les arguments subject, body permettent de personnaliser (un peu)
le mail qui sera envoyé.
le mail qui sera envoyé.
"""
nb = 0
if liste == None:
@ -367,15 +367,15 @@ class ControleMailer:
msg = u''
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'
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'
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'
if msg:
@ -388,11 +388,11 @@ class ControleMailer:
debug = debug)
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):
""" Comment ça marche ? """
""" Comment ça marche ? """
cprint(__doc__ % { 'prog': sys.argv[0] })
if message:
cprint(message)
@ -412,7 +412,7 @@ if __name__ == '__main__' :
elif opt in [ '-d', '--debug' ]:
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' ]:
if val in [ 'id', 'nom', 'cableur', 'date' ]:
@ -424,7 +424,7 @@ if __name__ == '__main__' :
tri_inverse = True
else:
__usage("option inconnue « %s »'" % opt)
__usage("option inconnue « %s »'" % opt)
if len(arg) == 0 or arg[0] == 'help':
__usage()
@ -456,14 +456,14 @@ if __name__ == '__main__' :
bureau = True
cableurs = mailer._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)
try:
body % u''
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)
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))
if bureau:
cprint(mailer.mail_bureau())

View file

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

View file

@ -1,20 +1,20 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
import sys
# Copyright (C) Stéphane Glondu, Alexandre Bos
# Copyright (C) Stéphane Glondu, Alexandre Bos
# Licence : GPLv2
__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.
__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.
Utilisation :
%(prog)s {lister|radier} [--debug <adresse>]
Les commandes sont :
* lister afficher la liste des câbleurs succeptibles d'être
radiés
* lister afficher la liste des câbleurs succeptibles d'être
radiés
* radier selectionner, parmis eux, les cableurs que l'on
souhaite radier
"""
@ -28,23 +28,23 @@ from email_tools import send_email, parse_mail_template
# Fonctions d'affichage
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
db = crans_ldap()
def _controle_interactif_adherents(liste):
"""
Demande ce qu'il faut faire à chaque fois
Demande ce qu'il faut faire à chaque fois
"""
restant = len(liste)
if restant == 0:
return 0, 0
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"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
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"Une autre réponse entraîne l'interruption du processus.")
cprint(u"Le format est [nb_restant] Nom, Prénom (aid).")
cprint(u"")
nb = 0
@ -58,9 +58,9 @@ def _controle_interactif_adherents(liste):
modifiable.droits([])
cprint(modifiable.save())
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':
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
def candidats():
@ -74,10 +74,10 @@ def candidats():
def lister():
"""
Afficher les câbleurs fantômes potentiels.
Afficher les câbleurs fantômes potentiels.
"""
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
for adh in todo_list:
print adh.prenom() + " " + adh.nom()
@ -86,7 +86,7 @@ def lister():
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()
@ -94,7 +94,7 @@ def controle_interactif():
_controle_interactif_adherents(todo_list)
def __usage(message=None):
""" Comment ça marche ? """
""" Comment ça marche ? """
cprint(__doc__ % { 'prog': sys.argv[0] })
if message:

View file

@ -18,11 +18,11 @@ except:
pass
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":
encoding = "ISO-8859-15"
encoding = 'UTF-8'
if 'TERM' in os.environ and os.environ['TERM'] != 'unknown':
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")
except:
# Sinon c'est surement de l'iso
return txt.decode("ISO8859-15")
return txt.decode("UTF-8")
def to_encoding(txt, enc=encoding):
return to_unicode(txt).encode(enc, 'ignore')

View file

@ -6,7 +6,7 @@
#: Envoyé à la ML disconnect@ en cas de déconnexion pour p2p
avertissement = u"""From: %(From)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"
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
deconnexion = u"""From: %(From)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"
Bonjour,
@ -81,7 +81,7 @@ Disconnect Team"""
#: Envoyé à la ML disconnect@ en cas de déconnexion pour p2p plusieurs fois
message_disconnect_multi = u"""From: %(from)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"
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
message_disconnect_hard = u"""From: %(from)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"
%(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
message_disconnect_multi = u"""From: %(from)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 !
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
def format_sender(sender, header_charset='ISO-8859-15'):
def format_sender(sender, header_charset='utf-8'):
"""
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
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
and UTF-8 that can represent all the characters occurring in the email.
The charset of the email will be the first one out of US-ASCII or UTF-8
that can represent all the characters occurring in the email.
Argument server maybe a string, indicating the name of the SMTP server, or
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
# provide, then fall back to UTF-8.
header_charset = 'ISO-8859-15'
header_charset = 'UTF-8'
# 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:
body.encode(body_charset)
except UnicodeError:

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

@ -1,9 +1,9 @@
#! /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
"""
@ -18,11 +18,11 @@ import config
from tempfile import NamedTemporaryFile
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
debug = 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):
"""Nom du lock"""
@ -39,7 +39,7 @@ class gen_config :
if self._locked : remove_lock(self.lockname())
def __del__(self) :
# Au cas où...
# Au cas où...
self.unlock()
def _restore(self) :
@ -54,12 +54,12 @@ class gen_config :
os.system('cp -f %s %s' % ( f.name, nom ) )
def _open_conf(self,nom,comment=None) :
""" Créé un fichier
si comment est fourni, insère une entète qui utilisera le caractère
""" Créé un fichier
si comment est fourni, insère une entète qui utilisera le caractère
de commentaire fourni
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 """
@ -89,15 +89,15 @@ class gen_config :
return fd
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.anim = anim('\tgénération fichiers')
self.anim = anim('\tgénération fichiers')
try :
warn = self._gen()
if warn :
self.anim.reinit()
print WARNING
if self.debug : sys.stderr.write(warn.encode("ISO-8859-15"))
if self.debug : sys.stderr.write(warn.encode("UTF-8"))
else :
self.anim.reinit()
print OK
@ -110,7 +110,7 @@ class gen_config :
return False
def restart(self) :
""" Redémarrage du service concerné """
""" Redémarrage du service concerné """
if not self.restart_cmd : return
self.lock()
self.anim = anim('\trestart')
@ -127,8 +127,8 @@ class gen_config :
self.unlock()
def reconfigure(self) :
""" Génère les fichiers puis redémarre le service
si la génération c'est bien passée """
""" Génère les fichiers puis redémarre le service
si la génération c'est bien passée """
cprint(u'Reconfiguration %s :' % self.__str__(), 'gras')
if self.gen_conf() :
return self.restart()

View file

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

View file

@ -1,9 +1,9 @@
#! /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
"""
import time, sys, re, hashlib, base64, os
@ -56,36 +56,36 @@ def netv6_to_arpa(net):
class dns(gen_config) :
"""
Génération des fichiers de configuration de bind9 :
* fichier DNS_CONF qui contient les définitions de zone conformément
à zone_template. Ce fichier doit être inclus à partir de la config statique
Génération des fichiers de configuration de bind9 :
* fichier DNS_CONF qui contient les définitions de zone conformément
à zone_template. Ce fichier doit être inclus à partir de la config statique
de bind
* 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
Leur entète est générée à partir de zone_entete.
* 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
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
zones_direct et les adresses de zones_reverse. Les données proviennent 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
la base LDAP
"""
######################################PARTIE DE CONFIGURATION
### Fichiers à écrire
# Répertoire d'écriture des fichiers de zone
DNS_DIR = '/etc/bind/generated/' # Avec un / à la fin
DNSSEC_DIR = '/etc/bind/signed/' # Avec un / à la fin
# Fichier de définition des zones pour le maître
### Fichiers à écrire
# Répertoire d'écriture des fichiers de zone
DNS_DIR = '/etc/bind/generated/' # Avec un / à la fin
DNSSEC_DIR = '/etc/bind/signed/' # Avec un / à la fin
# Fichier de définition des zones pour le maître
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"
### Sur quelles zones on a autorité ?
## En cas de modification de ces zones penser à regéner le fichier de
### Sur quelles zones on a autorité ?
## 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)
# Résolution directe
# Résolution directe
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 alias pour les enregistrement A AAAA CNAME TXT et SSHFP
zone_alias = config.dns.zone_alias
@ -97,7 +97,7 @@ la base LDAP
'adm.crans.org': 'adm.v6.crans.org',
'ferme.crans.org': 'ferme.v6.crans.org',
}
# Résolution inverse
# Résolution inverse
zones_reverse = config.dns.zones_reverse
zones_v6_to_net = {
'crans.eu': config.prefix["fil"][0],
@ -105,26 +105,26 @@ la base LDAP
'wifi.crans.org': config.prefix["wifi"][0],
'adm.crans.org': config.prefix["adm"][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],
}
### 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_private = []
ip_master_DNS = config.dns.master
zone_multicast = 'tv.crans.org'
### Liste des délégations de zone
# Pour les demandes de ces zones, le DNS dira d'aller voir les serveurs listés ici
### 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 noms des serveurs on met l'IP sans point ou le nom avec un point
DELEG = {
zone_multicast : [ 'sable.crans.org.' , 'mdr.crans.org.', 'freebox.crans.org.', 'ovh.crans.org.'] ,
}
### Serveurs de mail
# format : [ priorité serveur , .... ]
# format : [ priorité serveur , .... ]
MXs = ['10 redisdead.crans.org', '20 ovh.crans.org', '20 freebox.crans.org']
SRVs = [
'_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.',
]
# 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'] }
# /!\ Il faut faire attention au rollback des keys, il faudrait faire quelque chose d'automatique avec opendnssec
DS = {
@ -161,7 +161,7 @@ la base LDAP
}
### Entète des fichiers de zone
### Entète des fichiers de zone
zone_entete="""
$ORIGIN %(zone)s.
$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 "%(NOM_zone)s" {
type master;
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 "%(NOM_zone)s" {
type slave;
@ -190,10 +190,10 @@ zone "%(NOM_zone)s" {
};
"""
### Verbosité
# Si =2, ralera (chaine warnings) si machines hors zone trouvée
### Verbosité
# Si =2, ralera (chaine warnings) si machines hors zone trouvée
# 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
hostname = short_name(gethostname())
@ -208,8 +208,8 @@ zone "%(NOM_zone)s" {
return "DNS"
def reverse(self, net, ip):
"""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
"""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
mettre dans le fichier de zone."""
n = netaddr.IPNetwork(net)
a = netaddr.IPAddress(ip)
@ -228,7 +228,7 @@ zone "%(NOM_zone)s" {
zone_reverse=netv4_to_arpa(config.NETs['multicast'][0])[0]
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] :
DNS += '@\tIN\tNS %s\n' % d
DNS += '\n'
@ -238,9 +238,9 @@ zone "%(NOM_zone)s" {
lignes_d +='@\tIN\tA\t%s\n' % '138.231.136.243'
for line in sap:
[nom,ip]=line.split(':')
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('[ .():,"\'+<>]','',nom) # on enlève tous les caractères illégaux
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('[ .():,"\'+<>]','',nom) # on enlève tous les caractères illégaux
nom=nom.lower()
try:
[ip1,ip2,ip3,ip4]=ip.strip().split('.')
@ -248,7 +248,7 @@ zone "%(NOM_zone)s" {
lignes_d +='%s\tIN\tA\t%s' % (nom,ip)
except:
pass
# Écriture de la zone directe
# Écriture de la zone directe
file = self.DNS_DIR + 'db.' + self.zone_multicast
fd = self._open_conf(file,';')
fd.write(self.zone_entete % \
@ -258,7 +258,7 @@ zone "%(NOM_zone)s" {
fd.write(lignes_d)
fd.close()
# Écriture du reverse
# Écriture du reverse
file = self.DNS_DIR + 'db.' + zone_reverse
fd = self._open_conf(file,';')
fd.write(self.zone_entete % \
@ -270,7 +270,7 @@ zone "%(NOM_zone)s" {
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.extend(self.zones_v4_to_v6.values())
@ -297,13 +297,13 @@ zone "%(NOM_zone)s" {
fd.close()
def _gen(self) :
### 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 numéro de série du type AAAAMMJJNN (année, mois, jour, incrément par jour)
### 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 numéro de série du type AAAAMMJJNN (année, mois, jour, incrément par jour)
serial = time.time() + 1000000000
### 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 :
DNS += '@\tIN\tNS %s.\n' % d
DNS += '\n'
@ -311,7 +311,7 @@ zone "%(NOM_zone)s" {
### Serveurs de mail
MX='; Serveurs de mails\n'
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 += '\n'
@ -345,12 +345,12 @@ zone "%(NOM_zone)s" {
self.anim.iter=len(self.machines)
for machine in self.machines :
self.anim.cycle()
# Calculs préliminaires
# Calculs préliminaires
try :
nom , zone = machine.nom().split('.',1)
zone = zone.encode('iso-8859-1')
zone = zone.encode('utf-8')
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
# Le direct
@ -359,7 +359,7 @@ zone "%(NOM_zone)s" {
# Si la machine est une borne wifi, on ajoute la 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])
# 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():
try:
[algo_txt,key]=sshkey.split()[:2]
@ -378,7 +378,7 @@ zone "%(NOM_zone)s" {
for alias in self.zone_alias[zone]:
direct[alias] = direct.get(alias, "") + ligne
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
if zone in self.zones_v4_to_v6:
@ -406,23 +406,23 @@ zone "%(NOM_zone)s" {
# Le direct avec 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
if alias in self.zones_direct :
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
if alias in self.zone_alias:
for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne
if machine.dnsIpv6():
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
if alias in self.zone_alias:
for alias2 in self.zone_alias[alias]: direct[alias2] = direct.get(alias2, "") + ligne
if alias in self.zones_v4_to_v6:
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]
direct[zone6] = direct.get(zone6, '') + ligne
if alias in self.zone_alias:
@ -445,9 +445,9 @@ zone "%(NOM_zone)s" {
ok = 1
break
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
zone = zone.encode('iso-8859-1')
zone = zone.encode('utf-8')
ligne = "%s\tIN\tCNAME\t%s.\n" % ( nom, machine.nom() )
direct[zone] = direct.get(zone, '') + ligne
if zone in self.zones_v4_to_v6:
@ -468,40 +468,40 @@ zone "%(NOM_zone)s" {
base_ip = ip.split('.')
base_ip.reverse()
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())
try : 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'):
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() :
# MXs
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##"]
zone_rev, length = self.reverse(full_net_v6, netaddr.IPNetwork(full_net_v6).first)
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():
nom, zone = deleg.split('.',1)
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
for serv in self.DELEG[deleg]:
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 s in ds:
direct[zone] += s + '\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 = ''
for zone, lignes in direct.items() + reverse.items() :
if zone in self.zones_dnssec:
@ -523,7 +523,7 @@ zone "%(NOM_zone)s" {
else:
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.write(f)
fd.close()
@ -535,13 +535,13 @@ if __name__ == '__main__' :
from config import bcfg2_main
hostname = short_name(gethostname())
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.gen_slave()
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]):
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.gen_tv()
import subprocess
@ -551,10 +551,10 @@ if __name__ == '__main__' :
print ret[0].strip()
print ret[1].strip()
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]):
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):
print "Ce serveur est esclave! Lancez ce script sur %s, puis lancez bcfg2 ici" % bcfg2_main
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
# -*- 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
"""
@ -12,22 +12,22 @@ from gen_confs import gen_config
from ldap_crans import hostname
class dhcp(gen_config) :
""" Génération du fichier de configuration pour dhcpd (DHCPD_CONF)
Le fichier comporte une partie par réseau servi, chaque réseau
servi doit être une clef du dictionnaire reseaux, la valeur correspondante
est une chaine décrivant les options spécifiques à ce réseau.
""" Génération du fichier de configuration pour dhcpd (DHCPD_CONF)
Le fichier comporte une partie par réseau servi, chaque réseau
servi doit être une clef du dictionnaire reseaux, la valeur correspondante
est une chaine décrivant les options spécifiques à ce réseau.
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
# Fichier à écire
# Fichier à écire
if hostname == 'ragnarok' :
DHCPD_CONF='/etc/dhcpd.conf'
else :
DHCPD_CONF = '/etc/dhcp3/dhcpd.conf'
# Hotspot ENS plus utilisé...
# Hotspot ENS plus utilisé...
# elif hostname == 'ragnarok' :
# On rajoute les IP dynamiques
# base_conf = """
@ -47,7 +47,7 @@ class dhcp(gen_config) :
#"""
elif hostname == 'sable':
# Options communes à toutes les réseaux servis
# Options communes à toutes les réseaux servis
base_conf="""
# VLan accueil
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 :
base_conf = ''
# Réseaux servis avec leurs options spécifiques
# Réseaux servis avec leurs options spécifiques
# if hostname == 'zamok':
# reseaux = { '138.231.136.0/21' :
#"""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 domain-name-servers 10.42.0.1;""" }
# Options communes à toutes les réseaux servis
# Options communes à toutes les réseaux servis
base_dhcp="""
subnet %(network)s netmask %(netmask)s {
default-lease-time 86400;
@ -153,9 +153,9 @@ subnet %(network)s netmask %(netmask)s {
}
"""
### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement si réseau vide
### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement si réseau vide
verbose = 1
# if hostname == 'zamok':
@ -195,7 +195,7 @@ subnet %(network)s netmask %(netmask)s {
fd.write(self.base_conf)
for net, options in self.reseaux.items() :
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
d = param(net)
d['OPTIONS_RESEAU'] = options

View file

@ -1,9 +1,9 @@
#! /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
"""
import os
@ -63,15 +63,15 @@ class dydhcp:
conn.close()
class dhcp(gen_config) :
""" Génération du fichier de déclaration des hosts.
Chaque réseau servi doit être une clef du dictionnaire reseaux,
""" Génération du fichier de déclaration des hosts.
Chaque réseau servi doit être une clef du dictionnaire reseaux,
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
# Fichier à écire
# Fichier à écire
if hostname == 'sable':
restart_cmd = '/etc/init.d/isc-dhcp-server restart'
reseaux = { '138.231.136.0/21' : '/etc/dhcp3/generated/adherents.liste',
@ -114,9 +114,9 @@ class dhcp(gen_config) :
}
"""
### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement si réseau vide
### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement si réseau vide
verbose = 1
######################################FIN PARTIE DE CONFIGURATION
@ -145,7 +145,7 @@ class dhcp(gen_config) :
def _gen(self) :
"""Construction de la liste des machines appartenant à un réseau
"""Construction de la liste des machines appartenant à un réseau
"""
warnings = ''

View file

@ -1,7 +1,7 @@
#! /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
#"""Ce script permet de lancer la reconfiguration des divers services
@ -9,8 +9,8 @@
#Usage: %(prog)s options
#Les options possibles sont :
#\t%(options)s
#Les options avec = doivent être suivies d'un argument. Plusieurs
#arguments peuvent être founis pour une même option, les séparer par &
#Les options avec = doivent être suivies d'un argument. Plusieurs
#arguments peuvent être founis pour une même option, les séparer par &
#"""
import sys, signal, os, getopt
@ -68,19 +68,19 @@ class base_reconfigure:
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:
sys.stderr.write("Il faut être root\n")
sys.stderr.write("Il faut être root\n")
sys.exit(1)
if not to_do:
if debug:
print 'Lecture des services à redémarrer dans la base LDAP...'
print 'Lecture des services à redémarrer dans la base LDAP...'
auto = True
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():
# Services spéciaux portant sur plusieurs machines
# Services spéciaux portant sur plusieurs machines
to_add = self.__service_develop.get(serv.nom, [])
if to_add:
for nom in to_add:
@ -97,13 +97,13 @@ class base_reconfigure:
else:
auto = False
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():
# Au cas où le service porte sur plusieurs machines
# Au cas où le service porte sur plusieurs machines
service = serv.replace('%s-' % hostname, '')
if hasattr(self, service):
# Le service est à reconfigurer sur cette machine
# Le service est à reconfigurer sur cette machine
db.services_to_restart('-%s' % serv)
try:
m = getattr(self, service)
@ -125,17 +125,17 @@ class base_reconfigure:
if debug:
reste = db.services_to_restart()
if reste:
print "Reste à faire :"
print "Reste à faire :"
for s in reste:
try:
print '\t%s' % s
except UnicodeDecodeError:
print '\t%s: non imprimable' % s.nom
else:
print "Plus rien à faire"
print "Plus rien à faire"
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)
def _do(self, service, machines=None):
@ -180,8 +180,8 @@ class redisdead(base_reconfigure):
def mail_modif(self, trucs):
"""
trucs est une liste de recherches à effectuer dans la base
l'affichage des résultats formera le corps du mail
trucs est une liste de recherches à effectuer dans la base
l'affichage des résultats formera le corps du mail
"""
from supervison import mail
self._do(mail(trucs))
@ -238,7 +238,7 @@ class zbee(base_reconfigure):
class komaz(base_reconfigure):
# Mimétisme de ma part -- xhub
# Mimétisme de ma part -- xhub
def __fw6(self):
if not hasattr(self, '__real_fw6'):
from firewall6 import Update
@ -312,7 +312,7 @@ if __name__ == '__main__':
classe = eval(hostname)
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):
if nom[0] != '_':
if len(getargspec(getattr(classe, nom))[0]) > 1:
@ -330,7 +330,7 @@ if __name__ == '__main__':
sys.stderr.write('%s\n' % msg)
sys.exit(255)
debug = 1 # défaut
debug = 1 # défaut
to_do = {}
for opt, val in options:
@ -344,7 +344,7 @@ if __name__ == '__main__':
sys.exit(0)
elif opt == '--list':
print 'Services à redémarrer :'
print 'Services à redémarrer :'
for s in db.services_to_restart():
try:
print '\t%s' % s
@ -353,7 +353,7 @@ if __name__ == '__main__':
sys.exit(0)
elif opt == '--reconnect':
# Personnes à reconnecter
# Personnes à reconnecter
print 'Recherche des personnes en fin de sanction...'
c = db.search('blacklist=*')
services = []
@ -369,7 +369,7 @@ if __name__ == '__main__':
sys.exit(0)
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('&'):
if serv.find(',') != -1:
serv, arg = serv.split(',', 1)
@ -390,5 +390,5 @@ if __name__ == '__main__':
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)

View file

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

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

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

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
import time, commands
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
class conf_wifi_ng(gen_config) :
""" Génération de la configuration de isakmpd dans ISAKMPD_CONF
Le fichier est constitué en 5 parties :
1) Configuration générale insérée telle quelle
""" Génération de la configuration de isakmpd dans ISAKMPD_CONF
Le fichier est constitué en 5 parties :
1) Configuration générale insérée telle quelle
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
5) Ajout de net_crans
@ -21,8 +21,8 @@ class conf_wifi_ng(gen_config) :
"""
######################################PARTIE DE CONFIGURATION
# Fichiers à écrire
# Répertoire d'écriture des fichiers de zone
# Fichiers à écrire
# Répertoire d'écriture des fichiers de zone
ISAKMPD_CONF='/etc/isakmpd/isakmpd.conf'
# Correspondance MAC/IP
MACIP='/etc/wifi/wifi-update-ng/common/etc/macip'
@ -57,7 +57,7 @@ class conf_wifi_ng(gen_config) :
self.anim=anim('\tfin reconfigurations')
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"
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:
continue
self.anim=anim('\treconfiguration de %s' % borne.nom())
# 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
# On supprime le répertoire de travail
# 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
# On supprime le répertoire de travail
if os.path.isdir(WORK):
shutil.rmtree(WORK)
# On copie COMMON
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())
if not os.path.isdir(top):
top = DEFAULT
# On en copie aussi le contenu
for root, dirs, files in os.walk(top, topdown=True):
# On créé les répertoires
# On créé les répertoires
for name in dirs:
try:
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),
os.path.join("%s%s" % (WORK, root[len(top):]),
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":
fd = file(os.path.join(WORK, "etc", "nvram.updates"), "a")
data = { 'HOST': borne.nom().split('.')[0],
@ -113,7 +113,7 @@ NVRAM_wl0_radio=%(ON)d
NVRAM_crans_hotspot=%(HOTSPOT)d
""" % data)
# On complète par les variables de la NVRAM
# On complète par les variables de la NVRAM
for info in borne.nvram():
fd.write('variables="${variables} %s"\n' % info.split("=")[0])
fd.write("NVRAM_%s\n" % info)
@ -122,15 +122,15 @@ NVRAM_crans_hotspot=%(HOTSPOT)d
# On fait du menage
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)
# 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))
# 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()),
"%s/%s.tar.gz" % (TARGET, borne.nom()))
print OK
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))
fd = file(self.MACIP, "w")
for machine in clients + bornes:
@ -141,9 +141,9 @@ NVRAM_crans_hotspot=%(HOTSPOT)d
print OK
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]
Listen-on= 138.231.148.1
@ -202,7 +202,7 @@ Remote-ID= Net-%(HOST)s
ID-type= IPV4_ADDR
Address= %(IP)s
"""
# Dernière partie du fichier
# Dernière partie du fichier
net_crans="""
[Net-crans]
ID-type= IPV4_ADDR_SUBNET
@ -226,7 +226,7 @@ Netmask= 0.0.0.0
# Phase 2
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_template % data

View file

@ -51,7 +51,7 @@ droits = db.search("uid=%s" % script_utilisateur)['adherent'][0].droits()
isimprimeur = u"Imprimeur" in droits
iscontroleur = u'Tresorier' 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 os.path.exists(os.path.expanduser('~/.dialogrc')):
@ -1892,7 +1892,7 @@ def select(clas, quoi, mde=''):
s= ['', '', '', '', '', '', '', '', '', '']
def f(a):
try:
return unicode(a, 'iso-8859-15')
return unicode(a, 'utf-8')
except:
return a
while 1:

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
import sys
sys.path.append('/usr/scripts/gestion')
@ -15,7 +15,7 @@ for m in machines :
# texte pour la machine
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'destination : %s\n' % ', '.join(m.exempt())

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
import sys
sys.path.append('/usr/scripts/gestion')
@ -13,7 +13,7 @@ done = []
txts = []
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 :
continue
if m.proprietaire().__class__ == AssociationCrans :
@ -22,7 +22,7 @@ for m in machines :
# texte pour la machine
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()
if m.portTCPin() :
txt += u'ports TCP in : %s\n' % ' '.join(m.portTCPin())

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
import sys, re
from time import sleep
@ -37,11 +37,11 @@ class interroge_switch (threading.Thread) :
if (prise != None):
nom=sw.nom(None,prise)
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
# chaîne de caractères)
# Retourne les infos sur la machine (l'équivalent d'un whos, mais renvoie la
# chaîne de caractères)
def info_machine(mac):
s = []
db = crans_ldap()
@ -52,7 +52,7 @@ def info_machine(mac):
r = re.sub('\x1b\[1;([0-9]|[0-9][0-9])m', '', r)
s.append(r)
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)
@ -66,7 +66,7 @@ def trace_machine(mac, affiche_uplinks=False):
for t in tableau:
t.join()
resultat = u'Traçage de %s...\n' % mac
resultat = u'Traçage de %s...\n' % mac
tracage = u''
for t in tableau:

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- encoding: iso-8859-15 -*-
# -*- encoding: utf-8 -*-
# Stats sur les historiques
@ -13,22 +13,22 @@ import re
from time import mktime, strptime
def plat(chose):
"""Applatit une liste de liste. Hautement récursif."""
"""Applatit une liste de liste. Hautement récursif."""
if type(chose) != ListType:
return [chose]
return sum(map(lambda x: plat(x), chose), [])
def hist():
"""Récupère l'historique dans une base SQLite dont la connexion est returnée."""
# On récupèr les adhérents
"""Récupère l'historique dans une base SQLite dont la connexion est returnée."""
# On récupèr les adhérents
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())],
adherents)
historiques = plat(historiques)
# 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")
cur = con.cursor()
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
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
# #############################################################
# ..
# .... ............ ........
@ -28,7 +28,7 @@
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
# Fin
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_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"
# Fin
@ -88,10 +88,10 @@ def try_command(cmd, tmp_rep, error_msg):
def base_prix(path_pdf_file, color=False):
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
# convert seront entreposé
# nom_rep seras le dossier dans tmp ou tous les fichier créé par
# convert seront entreposé
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_ps_file = escapeForShell(path_pdf_file + ".ps")
error_msg = "ERREUR %%d : Fichier invalide. Aucun %s cree."
@ -113,14 +113,14 @@ def base_prix(path_pdf_file, color=False):
nom_rep,
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)
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),
nom_rep,
error_msg % "png")
# Récupère la liste des fichiers
# Récupère la liste des fichiers
list_filepng=os.listdir(nom_rep)
# Calcule le nombre de pixel
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
+ 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.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()

View file

@ -1,9 +1,9 @@
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
"""
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)
@ -28,7 +28,7 @@ def etat_canon():
'printing(4)\nrunning(2)' : u'Impression en cours',
'other(1)\ndown(5)' : u"Imprimante hors-service",
'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',
'printing(4)\nwarning(3)' : u'Impression en cours'
}
@ -53,15 +53,15 @@ def etat_canon():
def etat_laserjet():
""" Renvoie une liste des differents ecrans actuels du display de l'imprimante """
_dico = {
u"READY": u"Prête",
u"PrÁt": u"Prêt",
u"READY": u"Prête",
u"PrÁt": u"Prêt",
u"Pr menus, appuy \x1e": u"",
u"Powersave activÅ": u"En veille",
u"Verification": u"Vérification imprimante",
u"Powersave activÅ": u"En veille",
u"Verification": u"Vérification imprimante",
u"imprimante": u"",
u"PrÅchauffage": u"Préchauffage",
u"PrÅchauffage": u"Préchauffage",
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 KIT NETTOY": u"",
u"COMMANDER FOURNIT.": u"",

View file

@ -1,3 +1,3 @@
#! /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
#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
#LANG=fr_FR@euro
sudo -u respbats /usr/scripts/gestion/logreader/rsyslog_reader.py $*

View file

@ -1,3 +1,3 @@
#! /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
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
#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
# -*- coding: iso-8859-15 -*-
# 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}')
# -*- encoding: utf-8 -*-
def get_machine(unformated_mac):
mac = format_mac(unformated_mac)
return u"\n" + info_machine(mac) + u"\n" + trace_machine(mac)
###########################
# Import des commmandes : #
###########################
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')
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',
]
###########################################
# Récupération des tables de protocoles : #
###########################################
# On récupère les destinataires dans les arguments (très ad hoc)
recipients = sys.argv[2].split(',')
# On complète le message
requete = "SELECT nom,id_p2p from protocole_p2p"
curseur.execute(requete)
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:
macs = find_mac.findall(texte)
for mac in macs:
textes.append(get_machine(mac))
except:
# En cas d'exception, on envoie le traceback
import traceback
textes.append(u'\n')
textes.append(u''.join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)))
textes.append('\n-- \narpwatch_sendmail.py\n')
ip_src = resultat_p2p.group(3)
verif = iptools.AddrInNets (ip_src,reseau)
except ValueError:
continue #IP malformee
if verif :
try:
date = resultat_p2p.group(1)
id_p2p = int(protocole_p2p[resultat_p2p.group(2)])
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()
smtp.connect()
smtp.sendmail("arpwatch@crans.org", recipients, u''.join(textes).encode('UTF-8'))
smtp.quit()
# On remplit la base :
######################
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)
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
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
"""DESCRIPTION
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
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
derniereConnexion dans la base LDAP.
UTILISATION
@ -12,7 +12,7 @@ UTILISATION
ACTIONS POSSIBLES
%(acts)s"""
# Copyright (C) 2006 Stéphane Glondu
# Copyright (C) 2006 Stéphane Glondu
# Licence : GPLv2
@ -41,8 +41,8 @@ openlog('comptes_inactifs')
def nb_mails_non_lus(login):
"""
Renvoie le nombre de mails non lus de login, ou None si impossible à
déterminer.
Renvoie le nombre de mails non lus de login, ou None si impossible à
déterminer.
"""
try:
maildir = '/var/mail/%s/new' % login
@ -56,8 +56,8 @@ def nb_mails_non_lus(login):
class ComptesInactifs(object):
# 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
# 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
re = [re.compile(r'^(\w+\s+\d+\s+\d+:\d+:\d+).*(?:'
r'dovecot.*Login: user=<|'
r'sshd.*Accepted.*for '
@ -70,7 +70,7 @@ class ComptesInactifs(object):
self.dic = {}
def search(self, query, mode=''):
""" CransLdap.search allégé """
""" CransLdap.search allégé """
query = '(&(objectClass=cransAccount)(objectClass=adherent)(%s))' % query
result = db.conn.search_s(db.base_dn, db.scope['adherent'], query)
result = [db.make(x, mode) for x in result]
@ -79,13 +79,13 @@ class ComptesInactifs(object):
def commit_to_ldap(self):
"""
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
for (login, timestamp) in self.dic.items():
a = self.search('uid=%s' % login, 'w')
if not a:
# Probablement un adhérent récemment parti
# Probablement un adhérent récemment parti
continue
a = a[0]
if a._modifiable == 'w':
@ -93,7 +93,7 @@ class ComptesInactifs(object):
if a.modifs: total += 1
a.save()
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
syslog("LDAP(lock): derniereConnexion=<%s>, login=<%s>" %
(strftime("%b %d %H:%M:%S", localtime(timestamp)), login))
@ -101,7 +101,7 @@ class ComptesInactifs(object):
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
timestamp = int(timestamp)
@ -110,8 +110,8 @@ class ComptesInactifs(object):
def update_from_syslog(self, loglines):
"""
Met à jour le dico avec les lignes de syslog données.
Renvoie le nombre de lignes traitées.
Met à jour le dico avec les lignes de syslog données.
Renvoie le nombre de lignes traitées.
"""
annee = localtime(time())[0]
now = time() + 600
@ -124,8 +124,8 @@ class ComptesInactifs(object):
date = list(strptime(m.group(1), "%b %d %H:%M:%S"))
date[0] = annee
t = mktime(date)
# 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
# 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
if t > now:
date[0] = annee - 1
t = mktime(date)
@ -135,21 +135,21 @@ class ComptesInactifs(object):
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)
updated_entries = self.commit_to_ldap()
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("%(parsed_lines)s ligne(s) traitée(s)" % locals())
syslog("%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP" % locals())
if parsed_lines == 0 or updated_entries == 0:
sys.stderr.write("""Erreur lors de la mise à jour de la base LDAP :
%(parsed_lines)s ligne(s) traitée(s)
%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP
sys.stderr.write("""Erreur lors de la mise à jour de la base LDAP :
%(parsed_lines)s ligne(s) traitée(s)
%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP
""" % locals())
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 = [(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])))
for x in liste]
cprint(tableau(liste,
titre = (u'Login', u'Dernière connexion'),
titre = (u'Login', u'Dernière connexion'),
largeur = (20, 20)))
cprint(u"Total : %d" % len(liste))
def get_idle_accounts(self, since=32*24*3600):
"""
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,
pour être sûr).
connectés depuis since secondes, par défaut un mois (32 jours,
pour être sûr).
"""
limit = int(time()) - since
liste = self.search("derniereConnexion<=%d" % limit)
@ -176,20 +176,20 @@ class ComptesInactifs(object):
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.
"""
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
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
Total : %(anciens_total)d
Légende :
Légende :
- F : existence d'un .forward
- M : existence de mails non lus
@ -219,7 +219,7 @@ comptes_inactifs.py
else:
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)
alignements = ('d', 'g', 'c', 'c', 'c', 'c')
@ -237,9 +237,9 @@ comptes_inactifs.py
def do_spam(self):
"""
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
# Voir aussi template_path
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
# a-il-des mails non lus ?
if not mail: i += 1
# on incrémente
# on incrémente
stats[i] += 1
if i == 1:
# on laisse tranquilles les membres inscrits sans mails non
@ -303,7 +303,7 @@ comptes_inactifs.py
""" % total
send_email(mail_sender,
mail_report,
u"Récapitulatif des comptes inactifs",
u"Récapitulatif des comptes inactifs",
recapitulatif,
server = smtp,
debug = debug)

View file

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

View file

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

View file

@ -1,7 +1,7 @@
#! /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 $
import sys, os
@ -25,23 +25,23 @@ PIDFILE = "/var/run/dhcp-detect.pid"
# dhcp-server attendu
DHCPSERVER = '138.231.136.9'
# Interface à surveiller
# Interface à surveiller
INTERFACE = "crans"
# Adresse MAC
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")
# On met à jour ce paquet
# On met à jour ce paquet
tosend.getlayer(Ether).src = mac
tosend.getlayer(IP).chksum = None
tosend.getlayer(UDP).chksum = None
tosend.getlayer(BOOTP).chaddr = ''.join(map(lambda x: chr(int(x,16)),mac.split(":")+['0']*10))
tosend = Ether(tosend.build())
# Tableau associatif "mac" - "mailé pour la dernière fois"
# Tableau associatif "mac" - "mailé pour la dernière fois"
dejavu = {}
@ -88,7 +88,7 @@ def mail(paquet):
print "Envoi d'un mail...",
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 IP : %s
@ -99,7 +99,7 @@ Un DHCP pirate a
msg += u"\n"
msg += info_machine(mac_pirate)
msg += u"""
Merci de votre attention et à bientôt.
Merci de votre attention et à bientôt.
--
dhcp-detect.py
@ -111,10 +111,10 @@ dhcp-detect.py
print "ok"
# Réception d'une réponse
# Réception d'une réponse
def recoit(paquet):
# On affiche
print "Réception de : ", paquet.summary()
print "Réception de : ", paquet.summary()
# 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:
# DHCP pirate ?
@ -140,7 +140,7 @@ def get():
if __name__ == "__main__":
# On quitte les éventuelles instances démonisées en cours
# On quitte les éventuelles instances démonisées en cours
try:
pid = int(file(PIDFILE).read().strip())
os.kill(pid, 15)
@ -150,12 +150,12 @@ if __name__ == "__main__":
createDaemon()
file(PIDFILE, "w").write("%d\n" % os.getpid())
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()
openlog("dhcp-detect", LOG_PID)
syslog("Démarrage de dhcp-detect")
# On démarre le thread qui envoie régulièrement le paquet...
syslog("Démarrage de dhcp-detect")
# On démarre le thread qui envoie régulièrement le paquet...
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()

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- encoding: iso-8859-15 -*-
# -*- encoding: utf-8 -*-
###########################
@ -17,21 +17,21 @@ import re
sys.path.append('/usr/script/surveillance')
import strptime
# Définition de constantes :
# Définition de constantes :
############################
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')
# 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) !!!
pgsql.set_isolation_level(0)
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"
@ -56,7 +56,7 @@ for cellule in tableau:
# 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=([^ ]*).*")
@ -65,7 +65,7 @@ motif_virus = re.compile("^(.*) komaz .* Virus:([^ ]*).* SRC=([^ ]*).* DST=([^ ]
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")
@ -89,7 +89,7 @@ for log in filtre:
id_p2p = int(protocole_p2p[resultat_p2p.group(2)])
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
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)
@ -114,7 +114,7 @@ for log in filtre:
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
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 :
@ -136,7 +136,7 @@ for log in filtre:
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
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))

View file

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

View file

@ -1,13 +1,13 @@
#! /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
# 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.
#
# This program is free software; you can redistribute it and/or modify
@ -40,7 +40,7 @@ prise_chbre = {}
aujourdhui = datetime.date.today()
def trouve_chambre(bat, prise):
""" Trouve la chambre associée à une prise """
""" Trouve la chambre associée à une prise """
if prise in ('????', 'EXT', 'CRA'):
return prise
@ -59,7 +59,7 @@ def trouve_chambre(bat, prise):
def trouve_prise(chbre):
""" Trouve la prise associée à une chambre """
""" Trouve la prise associée à une chambre """
if chbre in ('EXT', '????', 'CRA'):
return chbre
@ -72,7 +72,7 @@ def trouve_prise(chbre):
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_p = 0
@ -93,7 +93,7 @@ def __calcul_max(table):
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)
if not erreur_prise:
@ -108,29 +108,29 @@ def __ajoute_ligne(errs, ligne, prise, mac, info=None):
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,
'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):
""" 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:
- nombre_mac_max: nombre maximal d'erreurs trouvées pour une mac
- 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:
- nombre_mac_max: nombre maximal d'erreurs trouvées pour une mac
- 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:
- nombre: nombre total d'erreurs survenues sur la prise
- nombre_max: nombre maximal d'erreurs trouvéss pour une mac
- macs: dico associant à une mac la liste des erreurs à partir de cette 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
- 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
- info: informations sur le propriétaire (vaut None pour la première table)
- 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)
- machine: la machine en question
- prise: la prise de 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:
@ -139,13 +139,13 @@ Si jour est sp
cprint(u"Impossible d'ouvrir le fichier %s" % fichier_log, 'rouge')
sys.exit(1)
# Les macs non trouvées
# Les macs non trouvées
errs_inconnue = {}
# Les pc connectés sur la mauvaise prise
# Les pc connectés sur la mauvaise prise
errs_prise = {}
# Les recherches déjà effectuées sur les macs
# Les recherches déjà effectuées sur les macs
mac_machine = {}
annee = None
@ -161,12 +161,12 @@ Si jour est sp
if annee == None:
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
else:
annee = aujourdhui.year
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
mois = nouveau_mois
@ -213,7 +213,7 @@ Si jour est sp
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:
@ -248,35 +248,35 @@ def __usage(err=''):
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:
return int(val)
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():
""" Aide """
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:
-h, --help affiche cette aide
-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
-n, --min-prise <nombre> nombre minimal d'erreurs sur une prise pour qu'elle soit reportée
-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
-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
-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
<date> peut être:
<date> peut être:
- une date absolue sous la forme AAAAMMJJ
- une date relative à aujourd'hui sous la forme +<nombre de jour>
Par exemple pour ne considérer que les deux dernier jours: +2
- une date relative à aujourd'hui sous la forme +<nombre de jour>
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)
@ -288,7 +288,7 @@ if __name__ == '__main__':
# Info que l'on veut afficher
aff_inconnue = True
aff_prise = True
# Date de départ
# Date de départ
jour = None
import getopt, time
@ -318,7 +318,7 @@ if __name__ == '__main__':
try:
jour = datetime.date(*(time.strptime(val, "%Y%m%d")[0:3]))
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:
cprint(u'Option inconnue: %s' % opt, 'rouge')
__usage()
@ -328,7 +328,7 @@ if __name__ == '__main__':
errs_inconnue, errs_prise = parse_auth_log(fichier_log, jour)
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:
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
# -*- encoding: iso-8859-15 -*-
# -*- encoding: utf-8 -*-
"""
Script d'envoi des statistiques des déconnections
et du trafic de la journée à disconnect@
Script d'envoi des statistiques des déconnections
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
"""
@ -111,9 +111,9 @@ liste_upload = tableau(data = [ (l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn(
titre = ['upload', 'download', 'proto', 'machine'],
largeur = [10, 10, 10, 40],
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)
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'],
largeur = [10, 10, 10, 30],
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 :
#######################
@ -170,7 +170,7 @@ liste_serveurs = tableau(data = liste_serveurs,
titre = ['upload', 'download', 'proto', 'serveur'],
largeur = [10, 10, 10, 30],
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
@ -178,7 +178,7 @@ liste_serveurs = tableau(data = liste_serveurs,
# Liste des IP des serveurs
gros_uploads_des_serveurs = stats(ip_crans=ips_serveurs,
show=['ip_crans', 'ip_ext'], upload_mini=50,
show_limit=100).encode('iso-8859-15')
show_limit=100).encode('utf-8')
############################
# Statistiques virus/p2p : #
@ -206,10 +206,10 @@ liste_etherunk = tableau(data = [[l[0], socket.getfqdn(str(l[1]))]
for l in curseur.fetchall()],
titre = ['nombre','ip'],
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"
curseur.execute(requete)
@ -220,9 +220,9 @@ for IP in infections:
liste_virus.append(["%s" % (str(hostname))])
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
WHERE date > timestamp 'now' - interval '1 day'
@ -237,10 +237,10 @@ for IP, compteur in curseur.fetchall():
liste_virus2 = tableau(data = liste_virus2,
titre = ['machine', 'nombre'],
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
WHERE date > timestamp 'now' - interval '1 day'
@ -255,7 +255,7 @@ for IP, compteur in curseur.fetchall():
liste_virus3 = tableau(data = liste_virus3,
titre = ['machine', 'nombre'],
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"
message = """From: %(From)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>
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
@ -282,23 +282,23 @@ Content-Type: text/plain; charset="iso-8859-15"
%(liste_etherunk)s
*Machines actuellement déconnectées pour virus*
*Machines actuellement déconnectées pour virus*
%(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
*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
*Statistiques de trafic des adhérents* (tout le trafic)
*Statistiques de trafic des adhérents* (tout le trafic)
%(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

View file

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