Merge branch 'master' of ssh://git.crans.org/git/usr-scripts

This commit is contained in:
root 2013-04-24 11:54:46 +02:00
commit a9b7d12314
57 changed files with 19532 additions and 17967 deletions

View file

@ -1,5 +1,5 @@
Configuration des scripts config -- Configuration des scripts
========================= ===================================
Table des matières : Table des matières :

View file

@ -1,5 +1,5 @@
Configuration des mails automatiquement envoyés mails -- Configuration des mails automatiquement envoyés
=============================================== ========================================================
Table des matières : Table des matières :

View file

@ -0,0 +1,7 @@
gen_confs.firewall4 -- Le pare-feu ipv4
=======================================
.. automodule:: gestion.gen_confs.firewall4
:members:
:special-members:

View file

@ -0,0 +1,10 @@
gen_confs -- Cr@ns Configuration Generator
==========================================
Table des matières :
.. toctree::
:maxdepth: 2
:glob:
*

View file

@ -1,5 +1,5 @@
gestion - scripts de gestion du Cr@ns gestion -- scripts de gestion du Cr@ns
===================================== ======================================
Table des matières : Table des matières :
@ -7,3 +7,4 @@ Table des matières :
:maxdepth: 2 :maxdepth: 2
config/index config/index
gen_confs/index

View file

@ -0,0 +1,5 @@
canon_wrapper -- Soumission de jobs à l'imprimante canon
========================================================
.. automodule:: impression.canon_wrapper
:members:

View file

@ -0,0 +1,11 @@
impression -- Scripts relatifs au service d'impression du Cr@ns
===============================================================
Table des matières :
.. toctree::
:maxdepth: 2
:glob:
*

View file

@ -12,6 +12,7 @@ Table des matières :
:maxdepth: 5 :maxdepth: 5
gestion/index gestion/index
impression/index
Indices and tables Indices and tables
================== ==================

View file

@ -2,27 +2,29 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import psycopg2 import psycopg2
from functools import wraps
try: conn = None
if __name__ == 'annuaires_pg_test': def _need_conn(f):
conn = psycopg2.connect(user='crans', database='switchs', host='localhost') """Décorateur à appliquer aux fonctions nécessitant une connexion pgsql"""
else: @wraps(f)
conn = psycopg2.connect(user='crans', database='switchs', host='pgsql.adm.crans.org') def first_connect(*args, **kwargs):
global conn
# Population de la tâble avec les bâtiments if conn == None:
cur = conn.cursor() if __name__ == 'annuaires_pg_test':
host='localhost'
cur.execute("SELECT DISTINCT batiment FROM prises") else:
bat_switchs = [i[0] for i in cur.fetchall()] host='pgsql.adm.crans.org'
cur.close() # "connecting …"
del cur conn = psycopg2.connect(user='crans', database='switchs', host=host)
except psycopg2.OperationalError: return f(*args, **kwargs)
bat_switchs = ["a", "b", "c", "g", "h", "i", "j", "m", "o", "p"] return first_connect
bat_switchs = ["a", "b", "c", "g", "h", "i", "j", "m", "o", "p"]
bat_manuels = [] bat_manuels = []
@_need_conn
def chbre_prises(batiment, chambre = None): def chbre_prises(batiment, chambre = None):
"""Correspondance chambre -> prise""" """Correspondance chambre -> prise"""
batiment = batiment.lower() batiment = batiment.lower()
@ -44,6 +46,7 @@ def chbre_prises(batiment, chambre = None):
raise ValueError("Batiment inexistant") raise ValueError("Batiment inexistant")
return ret return ret
@_need_conn
def chbre_commentaire(batiment, chambre): def chbre_commentaire(batiment, chambre):
""" Renvoie le commentaire associé à la chambre """ """ Renvoie le commentaire associé à la chambre """
global conn global conn
@ -55,6 +58,7 @@ def chbre_commentaire(batiment, chambre):
except TypeError: except TypeError:
raise ValueError("Chambre inexistante") raise ValueError("Chambre inexistante")
@_need_conn
def reverse(batiment, prise = None): def reverse(batiment, prise = None):
"""Correspondance prise -> chambre""" """Correspondance prise -> chambre"""
batiment = batiment.lower() batiment = batiment.lower()
@ -79,6 +83,7 @@ def reverse(batiment, prise = None):
raise ValueError("Batiment inexistant") raise ValueError("Batiment inexistant")
return ret return ret
@_need_conn
def is_crans(batiment, chambre): def is_crans(batiment, chambre):
"""Chambre cablee au Cr@ns ?""" """Chambre cablee au Cr@ns ?"""
batiment = batiment.lower() batiment = batiment.lower()
@ -87,6 +92,7 @@ def is_crans(batiment, chambre):
cur.execute("SELECT crans FROM prises WHERE (batiment, chambre) = (%s, %s)", (batiment, chambre)) cur.execute("SELECT crans FROM prises WHERE (batiment, chambre) = (%s, %s)", (batiment, chambre))
return cur.fetchone()[0] return cur.fetchone()[0]
@_need_conn
def is_connected(batiment, chambre): def is_connected(batiment, chambre):
"""Cablage physique effectue ?""" """Cablage physique effectue ?"""
batiment = batiment.lower() batiment = batiment.lower()
@ -95,6 +101,7 @@ def is_connected(batiment, chambre):
cur.execute("SELECT cablage_effectue FROM prises WHERE (batiment, chambre) = (%s, %s)", (batiment, chambre)) cur.execute("SELECT cablage_effectue FROM prises WHERE (batiment, chambre) = (%s, %s)", (batiment, chambre))
return cur.fetchone()[0] return cur.fetchone()[0]
@_need_conn
def crous_to_crans(batiment, chambre): def crous_to_crans(batiment, chambre):
"""Passage d'une chambre de CROUS a Cr@ns""" """Passage d'une chambre de CROUS a Cr@ns"""
batiment = batiment.lower() batiment = batiment.lower()
@ -207,7 +214,7 @@ uplink_prises={ 'a' :
# peuvent être utiles à connaître # peuvent être utiles à connaître
401: 'uplink->batp0', 402: 'uplink->batp-1', 401: 'uplink->batp0', 402: 'uplink->batp-1',
403: 'uplink->batp2', 403: 'uplink->batp-3', 403: 'uplink->batp2', 403: 'uplink->batp-3',
405: 'libre-service', 406: 'uplink->backbone', 405: 'libre-service', 406: 'uplink->bato-1',
}, },
'o' : 'o' :
{ {
@ -223,9 +230,9 @@ uplink_prises={ 'a' :
'A2': 'komaz-ens', 'B2': 'multiprise-wifi', 'A2': 'komaz-ens', 'B2': 'multiprise-wifi',
'A3': 'sable', 'B3': 'dyson', 'A3': 'sable', 'B3': 'dyson',
'A4': 'komaz', 'B4': 'fy', 'A4': 'komaz', 'B4': 'fy',
'A5': 'malloc-1', 'B5': 'switch-ilo', 'A5': 'zbee' , 'B5': 'switch-ilo',
'B6': 'vigile 0B', 'B6': 'vigile 0B',
'B7': 'daath', 'B7': 'kdell',
'B8': 'batb', 'B8': 'batb',
'B9': '2b', 'B9': '2b',
'B10': 'fz', 'B10': 'fz',

View file

@ -1,7 +1,13 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
""" Pour détecter les gens en chambre invalide, les prévenir, et supprimer leurs machines
en l'absence de réponse. Récupérer des IPs, c'est cool."""
# Codé par b2moo, commenté par 20-100, cr{itiqu|on}é par Nit # Codé par b2moo, commenté par 20-100, cr{itiqu|on}é par Nit
# <daniel.stan@crans.org>
# <legallic@crans.org>
# <samir@crans.org>
import datetime import datetime
import time import time
@ -10,13 +16,22 @@ import ldap_crans
conn = ldap_crans.CransLdap() conn = ldap_crans.CransLdap()
import sys import sys
#: envoyer un mail à chaque adhérent concerné
sendmails = False sendmails = False
if "--mail-all" in sys.argv: if "--mail-all" in sys.argv:
sendmails = True sendmails = True
import email.Header import email.Header
import os #: Envoyer un mail à respbats
sendmail_respbats = True
if "--no-mail" in sys.argv:
sendmail_respbats = False
DEBUG = False
if "--debug" in sys.argv:
DEBUG = True
import os
import config import config
year = config.ann_scol year = config.ann_scol
delai = config.demenagement_delai delai = config.demenagement_delai
@ -24,8 +39,10 @@ delai = config.demenagement_delai
import config.mails.demenagement import config.mails.demenagement
# On récupère ceux qui n'ont pas payé cette année # On récupère ceux qui n'ont pas payé cette année
bad_boys_e_s = conn.search('chbre=????&paiement=%d&paiement!=%d' % (year-1,year))['adherent'] if config.periode_transitoire:
bad_boys_e_s = conn.search('chbre=????&paiement=%d&paiement!=%d' % (year-1,year))['adherent']
else:
bad_boys_e_s = conn.search('chbre=????&paiement=%d' % year)['adherent']
now = time.time() now = time.time()
@ -46,7 +63,7 @@ for clandestin in bad_boys_e_s:
delta = now - kickout_date delta = now - kickout_date
ttl = delai*86400 - delta ttl = delai*86400 - delta
if ttl > 0: if ttl > 0:
if sendmails and machine_liste != []: if (sendmails and machine_liste != [] or DEBUG) and (ttl >= (delai - 1)*86400 or 0 < ttl <= 86400):
# On lui envoie un mail pour le prévenir # On lui envoie un mail pour le prévenir
to = clandestin.mail() to = clandestin.mail()
if not "@" in to: if not "@" in to:
@ -55,15 +72,14 @@ for clandestin in bad_boys_e_s:
"chambre" : exchambre, "chambre" : exchambre,
"jours" : int(ttl/86400) + 1, "jours" : int(ttl/86400) + 1,
"to" : to} "to" : to}
if DEBUG:
print mail
mailer = os.popen("/usr/sbin/sendmail -t", "w") mailer = os.popen("/usr/sbin/sendmail -t", "w")
mailer.write(mail.encode("utf-8") + "\n.") mailer.write(mail.encode("utf-8") + "\n.")
mailer.close() mailer.close()
else: else:
for m in machine_liste: for m in machine_liste:
# On n'a pas envie d'essayer de supprimer une machine qui a une blackliste
if len(m.blacklist_actif()) > 0:
continue
to_print.append( (clandestin.id(), m.ip(), m.id(), m.nom()) ) to_print.append( (clandestin.id(), m.ip(), m.id(), m.nom()) )
m2 = conn.search('mid=%s' % m.id(),mode='w')['machine'][0] m2 = conn.search('mid=%s' % m.id(),mode='w')['machine'][0]
m2.delete('Adherent sans chambre valide depuis %d jours' % delai) m2.delete('Adherent sans chambre valide depuis %d jours' % delai)
@ -74,7 +90,7 @@ if to_print != []:
hostnamemaxsize = max([len(i[3]) for i in to_print]) hostnamemaxsize = max([len(i[3]) for i in to_print])
template = u"| %%4s | %%-15s | %%4s | %%-%ss |\n" % (hostnamemaxsize) template = u"| %%4s | %%-15s | %%4s | %%-%ss |\n" % (hostnamemaxsize)
message = u"" message = u""
message += u"\nListe des machines supprimée pour chambre invalide depuis plus de %s jours :\n" % delai message += u"\nListe des machines supprimées pour chambre invalide depuis plus de %s jours :\n" % delai
tiret_line = u"+------+-----------------+------+-%s-+\n" % ("-" * hostnamemaxsize) tiret_line = u"+------+-----------------+------+-%s-+\n" % ("-" * hostnamemaxsize)
message += tiret_line message += tiret_line
message += template % ("aid", " ip", "mid", (" " * (max((hostnamemaxsize-8)/2,0)) + "hostname")) message += template % ("aid", " ip", "mid", (" " * (max((hostnamemaxsize-8)/2,0)) + "hostname"))
@ -86,7 +102,9 @@ if to_print != []:
headers += u"Content-Type: text/plain; charset=UTF-8\n" headers += u"Content-Type: text/plain; charset=UTF-8\n"
headers += u"To: respbats@crans.org\n" headers += u"To: respbats@crans.org\n"
mail = headers + "\n" + message mail = headers + "\n" + message
mailer = os.popen("/usr/sbin/sendmail -t", "w") if sendmails:
mailer.write(mail.encode("utf-8") + "\n.") mailer = os.popen("/usr/sbin/sendmail -t", "w")
mailer.close() mailer.write(mail.encode("utf-8") + "\n.")
mailer.close()
else:
print mail

View file

@ -168,7 +168,9 @@ NETs_regexp = { 'all' : '^138\.231\.1(3[6789]|4[0123456789]|5[01])\.\d+$' }
# ci-dessus... # ci-dessus...
rid = { rid = {
# Rid pour les machines fixes # Rid pour les machines fixes
'fil' : (256, 2047), 'adherents' : (256, 2047),
# Rid pour les machines filaire ipv4
'fil' : (0, 2047),
# Rid pour les machines wifi # Rid pour les machines wifi
'wifi' : (2048, 4095), 'wifi' : (2048, 4095),
# Rid pour les machines du vlan adm # Rid pour les machines du vlan adm
@ -204,7 +206,8 @@ ipv6_machines_speciales = {
# Les préfixes ipv6 # Les préfixes ipv6
prefix = { 'subnet' : [ '2a01:240:fe3d::/48' ], prefix = { 'subnet' : [ '2a01:240:fe3d::/48' ],
'serveurs' : [ '2a01:240:fe3d:4::/64'], 'serveurs' : [ '2a01:240:fe3d:4::/64' ],
'adherents' : [ '2a01:240:fe3d:4::/64' ],
'fil' : [ '2a01:240:fe3d:4::/64' ], 'fil' : [ '2a01:240:fe3d:4::/64' ],
'adm' : [ '2a01:240:fe3d:c804::/64' ], 'adm' : [ '2a01:240:fe3d:c804::/64' ],
'wifi' : [ '2a01:240:fe3d:c04::/64' ], 'wifi' : [ '2a01:240:fe3d:c04::/64' ],
@ -274,9 +277,12 @@ file_pickle = { 4 : '/tmp/ipt_pickle',
6 : '/tmp/ip6t_pickle' 6 : '/tmp/ip6t_pickle'
} }
blacklist_sanctions = ['upload', 'warez', 'p2p', 'autodisc_p2p','autodisc_virus','virus','autodisc_upload', 'bloq'] blacklist_sanctions = ['upload', 'warez', 'p2p', 'autodisc_p2p','autodisc_virus','virus', 'bloq']
if bl_carte_et_definitif:
blacklist_sanctions.append('carte_etudiant')
blacklist_sanctions_soft = ['autodisc_virus','ipv6_ra','mail_invalide','virus', blacklist_sanctions_soft = ['autodisc_virus','ipv6_ra','mail_invalide','virus',
'upload', 'warez', 'p2p', 'autodisc_p2p', 'autodisc_upload', 'bloq','carte_etudiant','chambre_invalide'] 'upload', 'warez', 'p2p', 'autodisc_p2p', 'bloq','carte_etudiant','chambre_invalide']
blacklist_bridage_upload = ['autodisc_upload']
adm_users = [ 'root', 'identd', 'daemon', 'postfix', 'freerad', 'amavis', adm_users = [ 'root', 'identd', 'daemon', 'postfix', 'freerad', 'amavis',
'nut', 'respbats', 'list', 'sqlgrey', 'ntpd', 'lp' ] 'nut', 'respbats', 'list', 'sqlgrey', 'ntpd', 'lp' ]

View file

@ -4,6 +4,28 @@
""" Variables de configuration pour le firewall """ """ Variables de configuration pour le firewall """
import datetime import datetime
#: Interfaces réseaux des machines ayant un pare-feu particulié
dev = {
'komaz': {
'out' : 'ens',
'wifi' : 'crans.3',
'fil' : 'crans',
'app' : 'crans.21',
'adm' : 'crans.2',
'tun-ovh' : 'tun-ovh'
},
'zamok': {
'fil' : 'crans',
'adm' : 'crans.2'
},
'routeur': {
'fil' : 'eth0',
'adm' : 'eth1',
'accueil' : 'eth2',
'isolement' : 'eth3',
'app' : 'eth4'
},
}
#: Pour marquer les paquets #: Pour marquer les paquets
mark = { 'https-radin': '0x3', mark = { 'https-radin': '0x3',
@ -28,3 +50,21 @@ else:
debit_max = 500 * 1024 / 8 # connexion de nuit et du week-end debit_max = 500 * 1024 / 8 # connexion de nuit et du week-end
#: Est-ce qu'on est en connexion de jour ou de nuit/week-end ? #: Est-ce qu'on est en connexion de jour ou de nuit/week-end ?
debit_jour = False debit_jour = False
#: Liste des réseaux non routables
reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12','198.18.0.0/15',
'169.254.0.0/16', '192.168.0.0/16', '224.0.0.0/4', '100.64.0.0/10',
'0.0.0.0/8','127.0.0.0/8','192.0.2.0/24','198.51.100.0/24','203.0.113.0/24',
]
#: Ports ouverts à défaut pour les adhérents dans le pare-feu
ports_default = {
'tcp' : {
'input' : [ '22' ],
'output' : [ ':24', '26:79', '80:134', '136', '140:444', '446:']
},
'udp' : {
'input' : [],
'output' : [ ':136','140:']
}
}

View file

@ -24,8 +24,8 @@ logiciels envoyant une très grande quantité de petites données
(vidéo-conférence par exemple). Il peut y avoir d'autres raisons. (vidéo-conférence par exemple). Il peut y avoir d'autres raisons.
Si cela continuait, et que tu dépassais la limite acceptable des 4096 Si cela continuait, et que tu dépassais la limite acceptable des 3789
Mo sur 24 heures, tu serais automatiquement déconnecté du réseau pour Mo sur 24 heures, ton débit serais automatiquement fortement limité pour
une durée de 24 heures. Il t'appartient donc de surveiller cela de une durée de 24 heures. Il t'appartient donc de surveiller cela de
plus près et de faire en sorte que tes machines n'uploadent pas de plus près et de faire en sorte que tes machines n'uploadent pas de
manière excessive à l'avenir. manière excessive à l'avenir.
@ -50,15 +50,13 @@ Content-Type: text/plain; charset="utf-8"
Bonjour %(proprio)s, Bonjour %(proprio)s,
Tu as temporairement été déconnecté du réseau en raison de l'envoi trop Ton débit à été temporairement limité en raison de l'envoi trop
important de données vers l'extérieur (%(upload)s Mo en 24h). important de données vers l'extérieur (%(upload)s Mo en 24h).
Tu as toujours accès au web ainsi qu'à tes mails crans mais tous les Si cela devait se renouveler trop souvent, tu serais déconnecté
autres services te sont suspendus. Si cela devait se renouveler trop complètement pour une durée plus importante.
souvent, tu serais déconnecté complètement pour une durée plus Il t'appartient donc de surveiller cela de plus près et de faire en sorte que
importante. Il t'appartient donc de surveiller cela de plus près et de ta machine n'uploade plus de manière excessive à l'avenir.
faire en sorte que ta machine n'uploade plus de manière excessive à
l'avenir.
Pour plus d'informations, tu peux consulter la page : Pour plus d'informations, tu peux consulter la page :
http://wiki.crans.org/VieCrans/DéconnexionPourUpload http://wiki.crans.org/VieCrans/DéconnexionPourUpload
@ -85,10 +83,10 @@ Message créé par deconnexion.py"""
#: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard #: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard
message_disconnect_hard = u"""From: %(from)s message_disconnect_hard = u"""From: %(from)s
To: %(to)s To: %(to)s
Subject: %(proprio)s a =?iso-8859-1?Q?=E9t=E9=20d=E9connect=E9?= Subject: %(proprio)s a =?iso-8859-1?Q?=E9t=E9=20brid=E9?=
Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8"
%(proprio)s a été déconnecté pour upload (%(upload)s Mo). %(proprio)s (aid=%(aid)s) a été limité en débit montant upload (%(upload)s Mo).
Ses machines ont été aperçues pour la dernière fois à ces endroits : Ses machines ont été aperçues pour la dernière fois à ces endroits :
%(mdc)s %(mdc)s
@ -101,11 +99,11 @@ Message créé par deconnexion.py"""
#: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard plusieurs fois #: Envoyé à la ML disconnect@ en cas de dépassement de la limite hard plusieurs fois
message_disconnect_multi = u"""From: %(from)s message_disconnect_multi = u"""From: %(from)s
To: %(to)s To: %(to)s
Subject: %(proprio)s a =?iso-8859-1?Q?=E9t=E9=20d=E9connect=E9?= Subject: %(proprio)s a =?iso-8859-1?Q?=E9t=E9=20brid=E9?=
%(nbdeco)d fois pour upload en un mois ! %(nbdeco)d fois pour upload en un mois !
Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8"
L'adhérent %(proprio)s a été déconnecté %(nbdeco)d fois pour upload en un mois ! L'adhérent %(proprio)s a été bridé %(nbdeco)d fois pour upload en un mois !
Le PS a été généré et se trouve sur zamok : Le PS a été généré et se trouve sur zamok :
%(ps)s %(ps)s

View file

@ -11,7 +11,7 @@ exempt = [ ['138.231.136.0/21', '138.231.0.0/16'],
soft = 300 soft = 300
#: limite hard #: limite hard
hard = 4096 hard = 3789
#: envoyer des mails à disconnect@ en cas de dépassement soft ? #: envoyer des mails à disconnect@ en cas de dépassement soft ?
disconnect_mail_soft = False disconnect_mail_soft = False

File diff suppressed because it is too large Load diff

View file

@ -46,7 +46,7 @@ class del_user:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
def delete_daath(self): def delete_zbee(self):
cprint(u'Archivage fichiers utilisateur', 'gras') cprint(u'Archivage fichiers utilisateur', 'gras')
for args in self.args: for args in self.args:
anim('\t' + args) anim('\t' + args)
@ -54,7 +54,7 @@ class del_user:
login, home = args.split(',') login, home = args.split(',')
if not login or not home: if not login or not home:
raise ValueError('Argument invalide') raise ValueError('Argument invalide')
if home.startswith('/home/') and hostname == "daath": if home.startswith('/home/') and hostname == "zbee":
home = "/home-adh/" + home[6:] home = "/home-adh/" + home[6:]
warn = '' warn = ''
f = '%s/files/%s_%s.tar.bz2' % ('/home-adh/cimetiere', f = '%s/files/%s_%s.tar.bz2' % ('/home-adh/cimetiere',
@ -85,8 +85,8 @@ class del_user:
traceback.print_exc() traceback.print_exc()
def reconfigure(self): def reconfigure(self):
if hostname == "daath": if hostname == "zbee":
self.delete_daath() self.delete_zbee()
elif hostname == "owl": elif hostname == "owl":
self.delete_directory(u"Suppression des fichiers index de dovecot", self.delete_directory(u"Suppression des fichiers index de dovecot",
"/var/dovecot-indexes/%s") "/var/dovecot-indexes/%s")
@ -110,9 +110,6 @@ class home:
except ValueError: except ValueError:
home, uid, login = args.split(',') home, uid, login = args.split(',')
mail_redirect = None mail_redirect = None
# Kludge pour daath (nfs) normalement inutile
if home.startswith('/home/') and hostname == "daath":
home = "/home-adh/" + home[6:]
### Home ### Home
if not os.path.exists(home): if not os.path.exists(home):
# Le home n'existe pas # Le home n'existe pas

1202
gestion/gen_confs/firewall4.py Executable file

File diff suppressed because it is too large Load diff

View file

@ -343,16 +343,16 @@ class firewall_crans :
if ip.startswith("138.231.1"): if ip.startswith("138.231.1"):
if machine.__class__.__name__ == "MachineWifi" and hostname != 'gordon': if machine.__class__.__name__ == "MachineWifi" and hostname != 'gordon':
# Machine Wifi, c'est la mac de gordon # Machine Wifi, c'est la mac de gordon
rules[self.mac_ip_set].append((ip,mac_wifi)) rules[self.mac_ip_set].append("%s,%s" % (ip,mac_wifi))
else: else:
# Machine fixe # Machine fixe
rules[self.mac_ip_set].append((ip,machine.mac())) rules[self.mac_ip_set].append("%s,%s" % (ip,machine.mac()))
if machine.__class__.__name__ == "MachineWifi" and hostname == 'komaz': if machine.__class__.__name__ == "MachineWifi" and hostname == 'komaz':
rules[self.mac_ip_set_wifi].append((ip,machine.mac())) rules[self.mac_ip_set_wifi].append("%s,%s" % (ip,machine.mac()))
elif machine.__class__.__name__ == "MachineWifi" and hostname != 'komaz': elif machine.__class__.__name__ == "MachineWifi" and hostname != 'komaz':
rules[self.mac_ip_set_wifi].append((ip,mac_komaz)) rules[self.mac_ip_set_wifi].append("%s,%s" % (ip,mac_komaz))
elif ip.startswith("10.231.136."): elif ip.startswith("10.231.136."):
rules[self.mac_ip_adm_set].append((ip,machine.mac())) rules[self.mac_ip_adm_set].append("%s,%s" % (ip,machine.mac()))
def mac_ip_gen(self): def mac_ip_gen(self):
self.anim = anim('\tChaîne TEST_MAC-IP', len(self.__machines())) self.anim = anim('\tChaîne TEST_MAC-IP', len(self.__machines()))
self.anim.reinit() self.anim.reinit()
@ -485,10 +485,10 @@ class firewall_komaz(firewall_crans) :
eth_adm = "crans.2" eth_adm = "crans.2"
# Ports ouverts # Ports ouverts
ports_default = { 'tcp_EXT_VERS_CRANS' : [ '22' ], ports_default = { 'tcp_EXT_VERS_CRANS' : config.firewall.ports_default['tcp']['input'],
'tcp_CRANS_VERS_EXT': [ ':24', '26:79', '80:134', '136', '140:444', '446:'], 'tcp_CRANS_VERS_EXT': config.firewall.ports_default['tcp']['output'],
'udp_EXT_VERS_CRANS' : [ ], 'udp_EXT_VERS_CRANS' : config.firewall.ports_default['udp']['input'],
'udp_CRANS_VERS_EXT': [ ':136','140:'] } 'udp_CRANS_VERS_EXT': config.firewall.ports_default['udp']['output'] }
# on retire 445 et 135 en tcp car plein de mac se font deconnecter # on retire 445 et 135 en tcp car plein de mac se font deconnecter
@ -512,10 +512,7 @@ class firewall_komaz(firewall_crans) :
ports_p2p = [ '412', '1214', '4662:4665' , '6346:6347', '6699', '6881:6889' ] ports_p2p = [ '412', '1214', '4662:4665' , '6346:6347', '6699', '6881:6889' ]
liste_reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12','198.18.0.0/15', liste_reseaux_non_routables = config.firewall.reseaux_non_routables
'169.254.0.0/16', '192.168.0.0/16', '224.0.0.0/4', '100.64.0.0/10',
'0.0.0.0/8','127.0.0.0/8','192.0.2.0/24','198.51.100.0/24','203.0.113.0/24',
'255.255.255.255/32']
def reseaux_non_routables(self) : def reseaux_non_routables(self) :
""" Construction de RESEAUX_NON_ROUTABLES_{DST,SRC} """ """ Construction de RESEAUX_NON_ROUTABLES_{DST,SRC} """
@ -1313,7 +1310,7 @@ class firewall_zamok(firewall_crans) :
# Pour le nfs (le paquet à laisser passer n'a pas d'owner) # Pour le nfs (le paquet à laisser passer n'a pas d'owner)
iptables("-A SERV_OUT_ADM -d fx.adm.crans.org -j ACCEPT") iptables("-A SERV_OUT_ADM -d fx.adm.crans.org -j ACCEPT")
iptables("-A SERV_OUT_ADM -d daath.adm.crans.org -j ACCEPT") iptables("-A SERV_OUT_ADM -d nfs.adm.crans.org -j ACCEPT")
# Rien d'autre ne passe # Rien d'autre ne passe
iptables("-A SERV_OUT_ADM -j REJECT --reject-with icmp-net-prohibited") iptables("-A SERV_OUT_ADM -j REJECT --reject-with icmp-net-prohibited")

View file

@ -4,14 +4,14 @@
# Copyright (C) Frédéric Pauget # Copyright (C) Frédéric Pauget
# Licence : GPLv2 # Licence : GPLv2
"""Ce script permet de lancer la reconfiguration des divers services #"""Ce script permet de lancer la reconfiguration des divers services
#
Usage: %(prog)s options #Usage: %(prog)s options
Les options possibles sont : #Les options possibles sont :
\t%(options)s #\t%(options)s
Les options avec = doivent être suivies d'un argument. Plusieurs #Les options avec = doivent être suivies d'un argument. Plusieurs
arguments peuvent être founis pour une même option, les séparer par & #arguments peuvent être founis pour une même option, les séparer par &
""" #"""
import sys, signal, os, getopt import sys, signal, os, getopt
@ -27,34 +27,30 @@ from syslog import *
import platform import platform
openlog("generate") openlog("generate")
# On vérifie que l'on est root
if os.getuid() != 0:
sys.stderr.write("Il faut être root\n")
sys.exit(1)
signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
db = crans_ldap() db = crans_ldap()
make_lock('auto_generate', 'Big lock', nowait=1) make_lock('auto_generate', 'Big lock', nowait=1)
class base_reconfigure: class base_reconfigure:
__firewalled_servers = [ 'redisdead', 'zamok', 'sable', 'komaz', 'gordon', 'routeur' ]
__blacklist_servers = [ _s + '-blacklist' for _s in __firewalled_servers ]
__service_develop = { __service_develop = {
'macip': [ 'redisdead-macip', 'zamok-macip', 'sable-macip', 'komaz-macip', 'gordon-macip', 'macip': [ _s + '-macip' for _s in __firewalled_servers ],
'routeur-macip' ],
# 'droits': [ 'rouge-droits', 'ragnarok-droits' ], # 'droits': [ 'rouge-droits', 'ragnarok-droits' ],
'bl_carte_etudiant':['komaz-blacklist'], 'bl_carte_etudiant': __blacklist_servers,
'bl_chbre_invalide':['komaz-blacklist'], 'bl_chbre_invalide': __blacklist_servers,
'blacklist_mail_invalide':['komaz-blacklist'], 'blacklist_mail_invalide': __blacklist_servers,
'blacklist_virus':['komaz-blacklist'], 'blacklist_virus': __blacklist_servers,
'blacklist_warez':['komaz-blacklist'], 'blacklist_warez': __blacklist_servers,
'blacklist_ipv6_ra':['komaz-blacklist'], 'blacklist_ipv6_ra': __blacklist_servers,
'blacklist_upload': ['komaz-blacklist', 'zamok-blacklist' ], 'blacklist_upload': __blacklist_servers,
'blacklist_p2p': ['komaz-blacklist', 'zamok-blacklist' ], 'blacklist_p2p': __blacklist_servers,
'blacklist_autodisc_virus':['komaz-blacklist'], 'blacklist_autodisc_virus': __blacklist_servers,
'blacklist_autodisc_upload': ['komaz-blacklist', 'zamok-blacklist'], 'blacklist_autodisc_upload': __blacklist_servers,
'blacklist_autodisc_p2p': ['komaz-blacklist', 'zamok-blacklist'], 'blacklist_autodisc_p2p': __blacklist_servers,
'blacklist_bloq': [ 'komaz-blacklist', 'zamok-blacklist', 'dns' ], 'blacklist_bloq': __blacklist_servers,
'del_user': [ 'daath-del_user', 'owl-del_user', 'zamok-del_user' ] 'del_user': [ 'zbee-del_user', 'owl-del_user', 'zamok-del_user' ]
} }
#Y R U Aliasing ! #Y R U Aliasing !
__service_develop.update({ __service_develop.update({
@ -72,6 +68,11 @@ class base_reconfigure:
def __init__(self, to_do=None): def __init__(self, to_do=None):
# On vérifie que l'on est root
if os.getuid() != 0:
sys.stderr.write("Il faut être root\n")
sys.exit(1)
if not to_do: if not to_do:
if debug: if debug:
print 'Lecture des services à redémarrer dans la base LDAP...' print 'Lecture des services à redémarrer dans la base LDAP...'
@ -144,14 +145,19 @@ class base_reconfigure:
service.machines = machines service.machines = machines
service.reconfigure() service.reconfigure()
def _fw(self):
if not hasattr(self, '__real_fw'):
from firewall4 import firewall
self.__real_fw = firewall()
return self.__real_fw
def macip(self, ips): def macip(self, ips):
if platform.dist()[1] >= '6':
import firewall_new
firewall = firewall_new
else:
import firewall
cprint(u"Mise a jour correspondance MAC-IP", 'gras') cprint(u"Mise a jour correspondance MAC-IP", 'gras')
eval("firewall.firewall_%s()" % hostname).mac_ip_maj(ips) self._fw().mac_ip_maj(ips)
def blacklist(self, ips):
cprint(u"Mise a jour des blacklists", 'gras')
self._fw().blacklist_maj(ips)
class redisdead(base_reconfigure): class redisdead(base_reconfigure):
def droits(self): def droits(self):
@ -215,11 +221,7 @@ class zamok(base_reconfigure):
from adherents import del_user from adherents import del_user
self._do(del_user(args)) self._do(del_user(args))
def blacklist(self): class zbee(base_reconfigure):
from firewall import firewall_zamok
firewall_zamok().blacklist()
class daath(base_reconfigure):
def home(self, args): def home(self, args):
from adherents import home from adherents import home
self._do(home(args)) self._do(home(args))
@ -235,11 +237,6 @@ class daath(base_reconfigure):
class komaz(base_reconfigure): class komaz(base_reconfigure):
def __fw(self):
if not hasattr(self, '__real_fw'):
from firewall_new import firewall_komaz
self.__real_fw = firewall_komaz()
return self.__real_fw
# Mimétisme de ma part -- xhub # Mimétisme de ma part -- xhub
def __fw6(self): def __fw6(self):
@ -251,33 +248,30 @@ class komaz(base_reconfigure):
def macip(self, ips): def macip(self, ips):
cprint(u"Mise a jour correspondance MAC-IP", 'gras') cprint(u"Mise a jour correspondance MAC-IP", 'gras')
self.__fw().mac_ip_maj(ips) self._fw().mac_ip_maj(ips)
self.__fw6().macs([], 6) self.__fw6().macs([], 6)
def ports(self, ips): def ports(self, ips):
self.__fw().port_maj(ips) self._fw().filtrage_ports_maj(ips)
#self.__fw6().ports(map(self.midt.from_ipv4, ips), 6) #self.__fw6().ports(map(self.midt.from_ipv4, ips), 6)
def blacklist(self): def blacklist(self, ips):
self.__fw().blacklist() self._fw().blacklist_maj(ips)
self.__fw6().blacklist(6) self.__fw6().blacklist(6)
def classify(self, ips): def classify(self, ips):
self.__fw().classes_p2p_maj(ips) #self.__fw().classes_p2p_maj(ips)
pass
class dyson(base_reconfigure): class dyson(base_reconfigure):
def autostatus(self): def autostatus(self):
from autostatus import autostatus from autostatus import autostatus
self._do(autostatus()) self._do(autostatus())
def dhcp(self):
from gen_confs.dhcpd_new import dhcp
self._do(dhcp(), self._machines())
class dhcp(base_reconfigure): class dhcp(base_reconfigure):
def dhcp(self): def dhcp(self):
from gen_confs.dhcpd_new import dhcp from gen_confs.dhcpd_new import dhcp
self._do(dhcp(), self._machines()) self._do(dhcp(), db.search("mid=*")['machine'])
class sable(base_reconfigure): class sable(base_reconfigure):
@ -285,10 +279,6 @@ class sable(base_reconfigure):
from gen_confs.bind import dns from gen_confs.bind import dns
self._do(dns(), self._machines()) self._do(dns(), self._machines())
def macip(self, ips):
from firewall_new import firewall_sable
firewall_sable().mac_ip_maj(ips)
class ovh(base_reconfigure): class ovh(base_reconfigure):
pass pass

View file

@ -17,13 +17,12 @@
import sys import sys
sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/gestion')
sys.path.append('/usr/scripts/lc_ldap')
import commands import commands
import lock import lock
import os
import lc_ldap
import secrets
class IpsetError(Exception): class IpsetError(Exception):
# Gestion des erreurs d'ipset # Gestion des erreurs d'ipset
@ -36,10 +35,23 @@ class IpsetError(Exception):
class Ipset(object): class Ipset(object):
ipset="/usr/sbin/ipset" ipset="/usr/sbin/ipset"
def __str__(self):
return self.set
def __init__(self,set,type,typeopt=''): def __init__(self,set,type,typeopt=''):
self.set=set self.set=set
self.type=type self.type=type
self.typeopt=typeopt self.typeopt=typeopt
self.squeeze = os.uname()[2] < '3'
try:
self.create()
except IpsetError as error:
if error.err_code != 256:
raise
elif not "already exists" in error.output:
raise
pass
def call(self,cmd,arg=''): def call(self,cmd,arg=''):
"""Appel système à ipset""" """Appel système à ipset"""
@ -71,15 +83,19 @@ class Ipset(object):
def restore(self,rules): def restore(self,rules):
""" restore le set courrant""" """ restore le set courrant"""
rules_str=self.restore_format(rules) rules_str=self.restore_format(rules)
create_str="-N %s %s %s" % (self.set,self.type,self.typeopt) if self.squeeze:
str="%s\n%s\nCOMMIT\n" % (create_str,rules_str) create_str="-N %s %s %s" % (self.set,self.type,self.typeopt)
str="%s\n%s\nCOMMIT\n" % (create_str,rules_str)
else:
str="%s\nCOMMIT\n" % rules_str
path='/tmp/ipset_%s' % self.set path='/tmp/ipset_%s' % self.set
f=open(path, 'w+') f=open(path, 'w+')
f.write(str) f.write(str)
f.close() f.close()
try: try:
self.flush() self.flush()
self.destroy() if self.squeeze:
self.destroy()
except IpsetError: pass except IpsetError: pass
cmd="cat %s | %s -R" % (path,self.ipset) cmd="cat %s | %s -R" % (path,self.ipset)
status,output=commands.getstatusoutput(cmd) status,output=commands.getstatusoutput(cmd)
@ -94,5 +110,5 @@ class Ipset(object):
self.call("-X") self.call("-X")
def restore_format(self,rules): def restore_format(self,rules):
return '\n'.join(["-A %s %s,%s" % (self.set,ip,mac) for (ip,mac) in rules]) return '\n'.join(["-A %s %s" % (self.set,data) for data in rules])

View file

@ -1,11 +1,11 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: iso-8859-15 -*- # -*- coding: utf-8 -*-
""" met à jour les propriétés des prises des switchs du bat : """ met à jour les propriétés des prises des switchs du bat :
mac autorisée(s), état (activé ou non) et nom de la prise mac autorisée(s), état (activé ou non) et nom de la prise
argument : nom du switch argument : nom du switch
procédure de configuration initiale : procédure de configuration initiale :
* mot de passe admin (password manager user-name <username>) * mot de passe admin (password manager user-name <username>)
* activation du ssh (crypto key generate ssh) * activation du ssh (crypto key generate ssh)
* copie fichier de conf * copie fichier de conf
@ -23,9 +23,10 @@ from ldap_crans import crans_ldap, BorneWifi
from annuaires_pg import uplink_prises, reverse, bat_manuels, all_switchs, bat_switchs from annuaires_pg import uplink_prises, reverse, bat_manuels, all_switchs, bat_switchs
from random import shuffle from random import shuffle
from gen_confs import * from gen_confs import *
from time import localtime import datetime
import config import config
import re import re
from crans.deprecated import deprecated
capture_model = re.compile(r'\((.*)\)') capture_model = re.compile(r'\((.*)\)')
headers_by_model = { headers_by_model = {
@ -38,27 +39,20 @@ headers_by_model = {
gigabit_models = ['J9021A', 'J9145A'] gigabit_models = ['J9021A', 'J9145A']
try:
any
except NameError:
def any(iterable):
for item in iterable:
if item:
return True
return False
class switch(gen_config) : class switch(gen_config) :
# Répertoire ou écire les fichiers de conf """Classe de configuration d'un switch"""
CONF_REP='/tmp/' # avec un / derrière # Répertoire ou écire les fichiers de conf
CONF_REP='/tmp/' # avec un / derrière
config = """%(switch_config_header)s config = """%(switch_config_header)s
hostname "%(switch)s" hostname "%(switch)s"
; Generated %(date_gen)s by switchs.py
%(module-type)s %(module-type)s
;-------------------------------------------------------- Snmp ;-------------------------------------------------------- Snmp
snmp-server contact "root@crans.org" snmp-server contact "root@crans.org"
snmp-server location "Batiment %(bat)s" snmp-server location "Batiment %(bat)s"
;A faire à la main ;A faire à la main
snmpv3 enable snmpv3 enable
snmpv3 restricted-access snmpv3 restricted-access
;snmpv3 user "initial" ;snmpv3 user "initial"
@ -121,7 +115,7 @@ vlan %(vlan_appts)s
exit exit
;-------------------------------------------------------- Logs ;-------------------------------------------------------- Logs
%(INTERFACES_CONF)s %(INTERFACES_CONF)s
;------------------------------------------------------- Accès d'administration ;------------------------------------------------------- Accès d'administration
no telnet-server no telnet-server
no web-management no web-management
aaa authentication ssh login public-key none aaa authentication ssh login public-key none
@ -144,7 +138,7 @@ no cdp run
no stack no stack
""" """
# Serveur DHCP des différent vlans # Serveur DHCP des différent vlans
dhcp_servers = { dhcp_servers = {
'1':'138.231.136.34', '1':'138.231.136.34',
'3':'138.231.148.34', '3':'138.231.148.34',
@ -187,7 +181,7 @@ exit
* un _tulpe_ de noms de switch => reconfig de ces swiths""" * un _tulpe_ de noms de switch => reconfig de ces swiths"""
self.db = crans_ldap() # connexion LDAP self.db = crans_ldap() # connexion LDAP
if type(truc) == list : if type(truc) == list :
# On enlève les chambres "CRA", "????" et EXT qui n'ont pas besion de config # On enlève les chambres "CRA", "????" et EXT qui n'ont pas besion de config
self.chbres = [ch for ch in truc if (ch not in [ "CRA", "????", "EXT" ]) ] self.chbres = [ch for ch in truc if (ch not in [ "CRA", "????", "EXT" ]) ]
self.switch = None self.switch = None
else : else :
@ -199,10 +193,10 @@ exit
def restart(self) : def restart(self) :
if self.chbre : if self.chbre :
# Tout est déja fait # Tout est déja fait
return return
####### Vu qu'il n'y a pas de serveur tftp ici ####### Vu qu'il n'y a pas de serveur tftp ici
# on excécute pas le truc en dessous # on excécute pas le truc en dessous
#for switch in self.switch : #for switch in self.switch :
# self.aff = anim('\treboot de %s' % switch) # self.aff = anim('\treboot de %s' % switch)
# sw = hptools.switch(switch) # sw = hptools.switch(switch)
@ -217,61 +211,11 @@ exit
for switch in self.switch : for switch in self.switch :
self.configure_switch(switch) self.configure_switch(switch)
@deprecated("Tous les switchs possèdent une authentification radius.")
def configure_chbre(self,chbre) : def configure_chbre(self,chbre) :
""" Recontigure la chambre fournie chambre """ """ Recontigure la chambre fournie chambre.
try : Déprécié. Tous les switchs possèdent une authentification radius."""
bat = chbre[0].lower() return False
if bat in bat_switchs :
prise = sw_chbre(chbre)
prise.reconfigure() # Vitesse et nom (juste au cas ou ca aurait changé)
elif bat in bat_manuels :
class prise_non_manageable :
def __init__(self,chbre) :
self.chbre = chbre
def __mail(self,sujet) :
To = "clef%s@crans.org" % self.chbre[0].lower()
From = To
conn=smtplib.SMTP('localhost')
txt_mail = "From: Crans scripts <%(From)s>\n"
txt_mail+= "To: %(To)s\n"
txt_mail+= "Subject: (CRANS) %s\n\nMerci." % sujet
conn.sendmail(From, To , txt_mail % { 'From' : From, 'To' : To })
conn.quit()
def disable(self) :
self.__mail("Chambre %s à débrancher." % self.chbre)
def enable(self) :
self.__mail("Chambre %s à brancher." % self.chbre)
prise=prise_non_manageable(chbre)
else :
# Rien a faire
print OK
return True
a = self.db.search('chbre=%s&paiement=ok' % chbre)
a = a['adherent'] + a['club']
if a and 'bloq' not in a[0].blacklist_actif() :
# Il faut activer la prise
anim('\tactivation chbre %s' % chbre)
prise.enable()
else :
# Il faut désactiver la prise
anim('\tdésactivation chbre %s' % chbre)
prise.disable()
print OK
except :
print ERREUR
if self.debug :
import traceback
traceback.print_exc()
return False
return True
def configure_switch(self,switch) : def configure_switch(self,switch) :
self.aff = anim('\tconfiguration de %s' % switch) self.aff = anim('\tconfiguration de %s' % switch)
@ -291,9 +235,9 @@ exit
return 1 return 1
def __configure_switch(self,switch) : def __configure_switch(self,switch) :
""" Génère le fichier de conf du switch donné """ """ Génère le fichier de conf du switch donné """
### Récupération données du switch ### Récupération données du switch
# Batiment et numéro du switch # Batiment et numéro du switch
bat = switch[3].lower() bat = switch[3].lower()
sw_num = int(switch[5]) sw_num = int(switch[5])
dhcp_servers = self.dhcp_servers dhcp_servers = self.dhcp_servers
@ -303,12 +247,13 @@ exit
self.aff.cycle() self.aff.cycle()
## On veut par défaut tout confier au serveur radius principal ## On veut par défaut tout confier au serveur radius principal
#shuffle(self.rad_servs) #shuffle(self.rad_servs)
rad = self.rad_template * len(self.rad_servs) rad = self.rad_template * len(self.rad_servs)
params = { 'switch' : switch, 'bat' : bat.upper() , params = { 'switch' : switch, 'bat' : bat.upper() ,
'date_gen': str(datetime.datetime.now()),
'radius_key' : radius_key , 'radius_key' : radius_key ,
'radius-serveurs' : rad[:-1] % tuple(self.rad_servs), 'radius-serveurs' : rad[:-1] % tuple(self.rad_servs),
} }
@ -328,7 +273,7 @@ exit
res, msg = commands.getstatusoutput("scp bat%s-%i:cfg/startup-config %s" % (bat, sw_num, old_config.name)) res, msg = commands.getstatusoutput("scp bat%s-%i:cfg/startup-config %s" % (bat, sw_num, old_config.name))
if res != 0: if res != 0:
raise RuntimeError(u"Erreur : impossible de récupérer l'ancienne configuration du switch") raise RuntimeError(u"Erreur : impossible de récupérer l'ancienne configuration du switch")
params['switch_config_header'] = old_config.readline() params['switch_config_header'] = old_config.readline()
old_config.close() old_config.close()
@ -346,7 +291,7 @@ exit
sys.stderr.write(model) sys.stderr.write(model)
params['switch_config_header']=headers_by_model[model] params['switch_config_header']=headers_by_model[model]
except: except:
sys.stderr.write('Impossible de déterminer le header à utiliser (switch %s)' % switch) sys.stderr.write('Impossible de déterminer le header à utiliser (switch %s)' % switch)
params['switch_config_header']= '; J4899A Configuration Editor; Created on release #H.10.50' params['switch_config_header']= '; J4899A Configuration Editor; Created on release #H.10.50'
model = params['switch_config_header'].split(' ', 2)[1] model = params['switch_config_header'].split(' ', 2)[1]
@ -357,10 +302,10 @@ exit
self.aff.cycle() self.aff.cycle()
# Nombre de prises et modèle # Nombre de prises et modèle
nb_prises = machine.nombrePrises() nb_prises = machine.nombrePrises()
if nb_prises < 0 : if nb_prises < 0 :
raise RuntimeError("Erreur : impossible de déterminer les caractéristiques du switch.") raise RuntimeError("Erreur : impossible de déterminer les caractéristiques du switch.")
has_dhcp_snooping = "2810" not in " ".join(machine.info()) has_dhcp_snooping = "2810" not in " ".join(machine.info())
@ -370,7 +315,7 @@ exit
# Dictionnaire prise -> chambre # Dictionnaire prise -> chambre
prise_chbres = reverse(bat) prise_chbres = reverse(bat)
# Prises occupées par des machines du Cr@ns # Prises occupées par des machines du Cr@ns
crans_prises={} crans_prises={}
for m in self.db.search('prise=%s%i*' % (bat.upper(), sw_num))['machine'] : for m in self.db.search('prise=%s%i*' % (bat.upper(), sw_num))['machine'] :
try: crans_prises[m.prise()].append(m) try: crans_prises[m.prise()].append(m)
@ -378,7 +323,7 @@ exit
self.aff.iter = nb_prises+1 self.aff.iter = nb_prises+1
# Paramètres à affecter # Paramètres à affecter
for key in ( 'uplinks', 'non_uplinks' ) : for key in ( 'uplinks', 'non_uplinks' ) :
params[key] = [] params[key] = []
@ -387,21 +332,21 @@ exit
'adm_tagged' : [] , 'adm_untagged' : [] , 'adm_tagged' : [] , 'adm_untagged' : [] ,
'appts_tagged' : [], 'appts_untagged' : [], 'appts_tagged' : [], 'appts_untagged' : [],
# VLans pour le reste: le vlan des adhérents, des # VLans pour le reste: le vlan des adhérents, des
# inconnus et de ceux qui ne paie pas # inconnus et de ceux qui ne paie pas
'default' : [] } 'default' : [] }
personnels_loges = self.db.search('etudes=Personnel ENS')['adherent'] personnels_loges = self.db.search('etudes=Personnel ENS')['adherent']
prises_appartements= [ p.chbre() for p in personnels_loges ] prises_appartements= [ p.chbre() for p in personnels_loges ]
# Génération de la conf de chaque prise # Génération de la conf de chaque prise
for prise in range(1,nb_prises+1): for prise in range(1,nb_prises+1):
self.aff.cycle() self.aff.cycle()
# Conf par défaut : activée, autonégociation # Conf par défaut : activée, autonégociation
prise_params = { 'prise' : prise , 'speed' : '', prise_params = { 'prise' : prise , 'speed' : '',
'etat' : '', 'no_flowcontrol': '' } 'etat' : '', 'no_flowcontrol': '' }
annu_prise = '%i%02i' % (sw_num, prise) # prise telle que notée dans l'annuaire annu_prise = '%i%02i' % (sw_num, prise) # prise telle que notée dans l'annuaire
if uplink_prises[bat].has_key(int(annu_prise)) : if uplink_prises[bat].has_key(int(annu_prise)) :
### Prise d'uplink ### Prise d'uplink
@ -419,7 +364,7 @@ exit
params['non_uplinks'].append(prise) params['non_uplinks'].append(prise)
if crans_prises.has_key("%s%s" % (bat.upper(), annu_prise)) : if crans_prises.has_key("%s%s" % (bat.upper(), annu_prise)) :
### Prise réservée à l'association ### Prise réservée à l'association
wifi=0 wifi=0
adm=0 adm=0
autres=0 autres=0
@ -466,7 +411,7 @@ exit
# chambres. # chambres.
chbres = prise_chbres.get(annu_prise, []) chbres = prise_chbres.get(annu_prise, [])
# Pour les switchs gigabit, on bloque le gigabit par défaut, sauf # Pour les switchs gigabit, on bloque le gigabit par défaut, sauf
# pour les membres actifs et les clubs (cf plus bas) # pour les membres actifs et les clubs (cf plus bas)
if model in gigabit_models: if model in gigabit_models:
prise_params['speed'] = 'speed-duplex auto-10-100' prise_params['speed'] = 'speed-duplex auto-10-100'
@ -478,7 +423,7 @@ exit
# On selectionne les eventuels adherents y residant # On selectionne les eventuels adherents y residant
residents = self.db.search("chbre=%s%s" % (bat, chb)) residents = self.db.search("chbre=%s%s" % (bat, chb))
for adherent in residents['adherent']: for adherent in residents['adherent']:
if adherent.droits(): #Seuls les membres actifs ont le droit à plus if adherent.droits(): #Seuls les membres actifs ont le droit à plus
prise_params['speed'] = '' prise_params['speed'] = ''
# On selectionne les machines fixes de l'adherent, et on ajoute le nombre au quota # On selectionne les machines fixes de l'adherent, et on ajoute le nombre au quota
nombre_de_machines += len(adherent.machines_fixes()) nombre_de_machines += len(adherent.machines_fixes())
@ -487,9 +432,9 @@ exit
# Authentification RADIUS, pas pour les clubs... # Authentification RADIUS, pas pour les clubs...
if not any("cl" in chbre.lower() for chbre in chbres): if not any("cl" in chbre.lower() for chbre in chbres):
# "unauth-vid" est le vlan sur lequel sont envoyés les machines # "unauth-vid" est le vlan sur lequel sont envoyés les machines
# quand l'authentification RADIUS échoue. On met le VLAN 1 pour # quand l'authentification RADIUS échoue. On met le VLAN 1 pour
# éviter les problèmes quand LDAP se ch@#! dessus. # éviter les problèmes quand LDAP se ch@#! dessus.
params['INTERFACES_CONF'] += """aaa port-access mac-based %(prise)s params['INTERFACES_CONF'] += """aaa port-access mac-based %(prise)s
aaa port-access mac-based %(prise)s addr-limit %(nbmac)s aaa port-access mac-based %(prise)s addr-limit %(nbmac)s
aaa port-access mac-based %(prise)s logoff-period 3600 aaa port-access mac-based %(prise)s logoff-period 3600
@ -497,11 +442,11 @@ aaa port-access mac-based %(prise)s unauth-vid 1
""" % { 'nbmac': 2 + nombre_de_machines, 'prise': prise } """ % { 'nbmac': 2 + nombre_de_machines, 'prise': prise }
# On regle le nombre de machines connectables a la prise au nombre de machines # On regle le nombre de machines connectables a la prise au nombre de machines
# sur cette prise dans l'annuaire plus 2 # sur cette prise dans l'annuaire plus 2
else: # ... et pour les clubs, vlans par défaut else: # ... et pour les clubs, vlans par défaut
vlans['default'].append(prise) vlans['default'].append(prise)
# On donne à la prise un nom qui dépend des chambres # On donne à la prise un nom qui dépend des chambres
# connectés dessus # connectés dessus
if chbres : if chbres :
prise_params['nom'] = 'Chambre' prise_params['nom'] = 'Chambre'
if len(chbres) > 1 : prise_params['nom'] += 's' if len(chbres) > 1 : prise_params['nom'] += 's'
@ -522,7 +467,7 @@ aaa port-access mac-based %(prise)s unauth-vid 1
# Petite verif # Petite verif
if not params['uplinks'] or not params['non_uplinks'] : if not params['uplinks'] or not params['non_uplinks'] :
raise RuntimeError('Switch sans uplink ou sans prise adhérent.') raise RuntimeError('Switch sans uplink ou sans prise adhérent.')
def mk_list(liste_prise) : def mk_list(liste_prise) :
""" """
@ -544,12 +489,12 @@ aaa port-access mac-based %(prise)s unauth-vid 1
if nouveau == groupe[1] + 1 : if nouveau == groupe[1] + 1 :
groupe[1] += 1 groupe[1] += 1
else : else :
# Ajout du groupe au résultat # Ajout du groupe au résultat
if groupe[0] == groupe[1] : if groupe[0] == groupe[1] :
result.append(str(groupe[0])) result.append(str(groupe[0]))
else : else :
result.append('-'.join(map(str,groupe))) result.append('-'.join(map(str,groupe)))
# Réinit de groupe # Réinit de groupe
groupe = [ nouveau, nouveau ] groupe = [ nouveau, nouveau ]
return ','.join(result) return ','.join(result)
@ -563,7 +508,7 @@ aaa port-access mac-based %(prise)s unauth-vid 1
for key, prises in vlans.items() : for key, prises in vlans.items() :
vlans[key]=mk_list(prises) vlans[key]=mk_list(prises)
# Config des vlans spéciaux (adm, wifi et appartements) # Config des vlans spéciaux (adm, wifi et appartements)
for v in ('adm', 'wifi', 'hotspot', 'appts') : for v in ('adm', 'wifi', 'hotspot', 'appts') :
params['prises_%s' % v] = '' params['prises_%s' % v] = ''
for t in ('tagged' , 'untagged') : for t in ('tagged' , 'untagged') :
@ -590,7 +535,7 @@ if __name__ == '__main__' :
opts, args = getopt.getopt(sys.argv[1:], 'hga', ['get-conf', 'help', 'all', 'header=' ]) opts, args = getopt.getopt(sys.argv[1:], 'hga', ['get-conf', 'help', 'all', 'header=' ])
if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) == 1 : if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) == 1 :
print "%s [-g|--get-conf] <switch>" % sys.argv[0].split('/')[-1].split('.')[0] print "%s [-g|--get-conf] <switch>" % sys.argv[0].split('/')[-1].split('.')[0]
print "Génération du fichier de configuration des switchs donnés." print "Génération du fichier de configuration des switchs donnés."
sys.exit(255) sys.exit(255)
if args[0] == 'all' or 'a' in opts or '--all' in opts : if args[0] == 'all' or 'a' in opts or '--all' in opts :

View file

@ -25,13 +25,14 @@ import os, re, syslog, cPickle, socket
from ldap_crans import crans_ldap, hostname from ldap_crans import crans_ldap, hostname
from commands import getstatusoutput from commands import getstatusoutput
from config import NETs, role, prefix, rid, output_file, filter_policy from config import NETs, role, prefix, rid, output_file, filter_policy
from config import blacklist_sanctions, blacklist_sanctions_soft, file_pickle, ann_scol, periode_transitoire from config import blacklist_sanctions, blacklist_sanctions_soft, blacklist_bridage_upload, file_pickle, ann_scol, periode_transitoire
from iptools import AddrInNet from iptools import AddrInNet
from ridtools import Rid from ridtools import Rid
import subprocess import subprocess
import netaddr import netaddr
blacklist_sanctions.extend(blacklist_sanctions_soft) blacklist_sanctions.extend(blacklist_sanctions_soft)
blacklist_sanctions.extend(blacklist_bridage_upload)
Mangle_policy = """ Mangle_policy = """
*mangle *mangle

View file

@ -119,6 +119,25 @@ def AddrInNets(ip,nets) :
return net return net
return '' return ''
def NetInNet(net1, net2) :
"""
net1 est de la forme xxx.xxx.xxx.xxx/yy
net2 est de la forme xxx.xxx.xxx.xxx/yy
Retourne True si net1 est un sous-réseaux de net2
"""
n1 = param(net1, raw=True)
n2 = param(net2, raw=True)
s1 = net1.split('/')[1]
s2 = net1.split('/')[1]
return s1<=s2 and (n1['network'] == n2['network'] or AddrInNet(DecToQuad(n1['network']), net2))
def NetInNets(net1, nets):
""" Vérifie si le premier paramètre est un sous-réseau des réseaux de la liste du second paramètre"""
for net in nets:
if NetInNet(net1, net) :
return net
return ''
def is_crans(ip): def is_crans(ip):
""" Vérifie que l'ip est dans le réseau CRANS """ Vérifie que l'ip est dans le réseau CRANS
""" """

View file

@ -9,7 +9,8 @@
'''Bibliothèque pour accéder à la baie de stockage nols, récupère les données '''Bibliothèque pour accéder à la baie de stockage nols, récupère les données
formatées en XML''' formatées en XML'''
import telnetlib, re import telnetlib
import re
from xml.etree.ElementTree import ElementTree, fromstring from xml.etree.ElementTree import ElementTree, fromstring
# Message envoyé par le serveur pour attendre l'appuie sur touche # Message envoyé par le serveur pour attendre l'appuie sur touche
@ -24,6 +25,11 @@ password = ""
# Récupère des identifiants # Récupère des identifiants
execfile("/etc/crans/secrets/nols.py") execfile("/etc/crans/secrets/nols.py")
class NolsError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
class Nols(object): class Nols(object):
'''Objet représentant la baie de stockage''' '''Objet représentant la baie de stockage'''
@ -83,6 +89,9 @@ class Nols(object):
# Remplace les fins de ligne dos par des fin de lignes unix # Remplace les fins de ligne dos par des fin de lignes unix
resp = crlf_regexp.sub("\n", resp) resp = crlf_regexp.sub("\n", resp)
if resp.lower().startswith("error"):
raise NolsError(resp.replace("Error: ", ""))
return resp return resp
def show(self, what): def show(self, what):
@ -152,7 +161,7 @@ class Nols(object):
while lun in map: lun = lun + 1 while lun in map: lun = lun + 1
# Création du volume # Création du volume
self.cmd("create volume vdisk %s size %d%s lun %d %s" % (vdisk, size, unit, lun, name)) result = self.cmd("create volume vdisk %s size %d%s lun %d %s" % (vdisk, size, unit, lun, name))
print "Le volume %s a été créé, son numéro d'identification est %d" %(name, lun) print "Le volume %s a été créé, son numéro d'identification est %d" %(name, lun)

View file

@ -8,7 +8,7 @@ Copyright (C) Alexandre Bos, largement pompe sur ldap_crans.py
Licence : GPLv2 Licence : GPLv2
""" """
import sys
from config import NETs from config import NETs
from iptools import AddrInNet from iptools import AddrInNet
try: try:
@ -79,13 +79,20 @@ def update_ip_wifi_adh(occupees):
update_ip('wifi-adh','ip_wifi-adh', occupees) update_ip('wifi-adh','ip_wifi-adh', occupees)
if __name__ == "__main__": if __name__ == "__main__":
dlg = Dialog() if "--cron" in sys.argv:
dlg.gauge_start(text="Recherche des machines...", backtitle="numeros_disponibles") cron = True
else:
cron = False
if not cron:
dlg = Dialog()
dlg.gauge_start(text="Recherche des machines...", backtitle="numeros_disponibles")
ip_occupees = lister_ip_utilisees() ip_occupees = lister_ip_utilisees()
done = 1 done = 1
for net in NETs.keys(): for net in NETs.keys():
dlg.gauge_update(int(done*100/(len(NETs)+1)), text="IP libres dans %s" % net, update_text=True) if not cron:
dlg.gauge_update(int(done*100/(len(NETs)+1)), text="IP libres dans %s" % net, update_text=True)
update_ip(net, ip_occupees) update_ip(net, ip_occupees)
done += 1 done += 1
dlg.gauge_update(100, text="Fini !", update_text=True) if not cron:
dlg.gauge_stop() dlg.gauge_update(100, text="Fini !", update_text=True)
dlg.gauge_stop()

View file

@ -445,23 +445,23 @@ def ressuscite_adherent(old):
title=u"Compte existant") title=u"Compte existant")
if no: if no:
return return
if True: if True:
# On croise les doigts # On croise les doigts
try: try:
modlist = ldap.modlist.addModlist(data) modlist = ldap.modlist.addModlist(data)
db.conn.add_s(dn, modlist) db.conn.add_s(dn, modlist)
dlg.msgbox(text=u"Résurrection effectée ! Veuillez maintenant restaurer le home et les mails", dlg.msgbox(text=u"Résurrection effectée ! Veuillez maintenant restaurer le home et les mails",
title=u"Fin") title=u"Fin")
# Au cas où l'adhérent avait des droits # Au cas où l'adhérent avait des droits
db.services_to_restart('droits') db.services_to_restart('droits')
# On notifie après une résurrection # On notifie après une résurrection
db.services_to_restart('mail_modif', ['uid=' + login]) db.services_to_restart('mail_modif', ['uid=' + login])
except Exception, e: except Exception, e:
dlg.msgbox(text=unicode(e), title=u"Erreur") dlg.msgbox(text=unicode(e), title=u"Erreur")
else: else:
print data print data
raise ValueError("debug") raise ValueError("debug")
def ressuscite_club(old): def ressuscite_club(old):
"""Ressuscite une instance d'un club""" """Ressuscite une instance d'un club"""

0
impression/__init__.py Normal file
View file

View file

@ -1,9 +1,14 @@
#!/usr/bin/python #!/usr/bin/python
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
# canon_wrapper.py #canon_wrapper.py
# Authors: Daniel STAN <dstan@crans.org> """
# Antoine Durand-Gasselin <adg@crans.org> .. codeauthor:: Daniel STAN <dstan@crans.org>
# License: GPLv3 .. codeauthor:: Antoine Durand-Gasselin <adg@crans.org>
Pour envoyer des jobs d'impression à l'imprimante canon via son interface web.
License: GPLv3
"""
import requests #pip install requests import requests #pip install requests
# See: # See:
@ -106,6 +111,7 @@ def build_url(name):
def range_checker(a, b): def range_checker(a, b):
"""Type function for a given range"""
def cast(x): def cast(x):
try: try:
v = int(x) v = int(x)
@ -117,6 +123,7 @@ def range_checker(a, b):
return cast return cast
def build_parser(): def build_parser():
"""Make argparse object"""
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="HTTP printing driver for irc3580, with compatibility mode.", description="HTTP printing driver for irc3580, with compatibility mode.",
epilog="logs are sent to syslog (eg /var/log/canon_wrapper.log)", epilog="logs are sent to syslog (eg /var/log/canon_wrapper.log)",
@ -159,6 +166,7 @@ def build_parser():
return parser return parser
def do_print(args): def do_print(args):
"""Effectively compatibilize then print the file"""
opt=build_options(args) opt=build_options(args)
syslog('Options: %s' % repr(opt)) syslog('Options: %s' % repr(opt))
#syslog('Starting ghostscript compat, piped mode') #syslog('Starting ghostscript compat, piped mode')
@ -205,3 +213,7 @@ if __name__ == '__main__':
syslog('Caught exception %s' % repr(e)) syslog('Caught exception %s' % repr(e))
raise raise
else:
parser = build_parser()
__doc__ += '''\nHelp message : ::\n\n'''
__doc__ += '\n'.join(' ' + l for l in parser.format_help().split('\n')) + "\n"

View file

@ -202,7 +202,7 @@ class impression:
# on compte les pages et on regarde le format # on compte les pages et on regarde le format
pdfinfo = Popen(["pdfinfo",self._fichier],stdout=PIPE,stderr=PIPE).communicate() pdfinfo = Popen(["pdfinfo",self._fichier],stdout=PIPE,stderr=PIPE).communicate()
if pdfinfo[1] <> '': if pdfinfo[1] <> '':
raise FichierInvalide(u"pdfinfo n'arrive pas a lire le fichier (il est peut-etre corrompu ou protege par un mot de passe)",path_to_pdf) raise FichierInvalide(u"pdfinfo n'arrive pas a lire le fichier (il est peut-etre corrompu ou protege par un mot de passe), https://wiki.crans.org/VieCrans/ImpressionReseau#Format_des_fichiers",path_to_pdf)
self._pages = -1 self._pages = -1
for line in pdfinfo[0].split('\n'): for line in pdfinfo[0].split('\n'):
if line.startswith('Pages'): if line.startswith('Pages'):
@ -378,6 +378,8 @@ class impression:
""" """
self._jid = _uniq_jid() self._jid = _uniq_jid()
# imprime le document
self._exec_imprime()
# debite l'adhérent si adherent il y a # debite l'adhérent si adherent il y a
if (self._adh != None): if (self._adh != None):
adh = self._adh.split('@') adh = self._adh.split('@')
@ -389,9 +391,6 @@ class impression:
adh.solde(-self._prix, "impression(%d): %s par %s" % (self._jid,self._fichier,self._adh)) adh.solde(-self._prix, "impression(%d): %s par %s" % (self._jid,self._fichier,self._adh))
adh.save() adh.save()
del adh del adh
# imprime le document
self._exec_imprime()
def _calcule_prix(self): def _calcule_prix(self):

View file

@ -23,6 +23,7 @@ import smtplib
from ldap_crans import crans_ldap from ldap_crans import crans_ldap
last_print_filename = "/var/run/print_status/last_print.txt" last_print_filename = "/var/run/print_status/last_print.txt"
error_filename = "/var/run/print_status/error.txt"
# Cette chaîne est utilisée pour construire une regexp, il faut que ce soit une chaîne brute. # Cette chaîne est utilisée pour construire une regexp, il faut que ce soit une chaîne brute.
files_directory = r"/var/impression/fichiers/" files_directory = r"/var/impression/fichiers/"
printer_host = "imprimante.adm.crans.org" printer_host = "imprimante.adm.crans.org"
@ -102,11 +103,25 @@ def sendMail(from_addr, to_addrs, mail_content):
http = httplib2.Http() http = httplib2.Http()
# On récupère la liste des tâches. Pour faire la requête, on doit récupérer un cookie de session. # On récupère la liste des tâches. Pour faire la requête, on doit récupérer un cookie de session.
headers, _ = http.request("http://" + printer_host + "/twelcome.cgi?CorePGTAG=0&Dummy=" + getMSE()) try:
_, content = http.request("http://" + printer_host + "/pprint.csv?Flag=Csv_Data&LogType=0&Dummy=" + getMSE(), 'GET', headers={'Cookie': headers['set-cookie']}) headers, _ = http.request("http://" + printer_host + "/twelcome.cgi?CorePGTAG=0&Dummy=" + getMSE())
_, content = http.request("http://" + printer_host + "/pprint.csv?Flag=Csv_Data&LogType=0&Dummy=" + getMSE(), 'GET', headers={'Cookie': headers['set-cookie']})
except:
# En cas derreur sur limprimante, plutôt que de spamer sur roots@crans.org, on note léchec quelque part à lattention dun service de monitoring.
error_file = open(error_filename, "w+")
error_file.write("Limprimante semble injoignable.")
error_file.close()
exit(0)
task_list = content.split('\n') task_list = content.split('\n')
# On enlève les entêtes et les deux lignes vides à la fin de la liste. # On vérifie que ce quon a récupéré ressemble à du CSV. Si tout se passe bien, limprimante envoie 13 champs par tâche.
task_list.pop(0) # On fait le test sur les entêtes, ce qui permet de sen débarasser au passage.
if len(task_list.pop(0).split(',')) != 13:
error_file = open(error_filename, "w+")
error_file.write("La liste des tâches renvoyée par limprimante na pas le format attendu.")
error_file.close()
exit(0)
# On enlève aussi les deux lignes vides à la fin de la liste.
task_list.pop() task_list.pop()
task_list.pop() task_list.pop()
@ -137,7 +152,7 @@ tasks_to_treat.reverse()
for item in tasks_to_treat: for item in tasks_to_treat:
fields = item.split(',', 6) fields = item.split(',', 6)
# On met à jour le numéro de la dernière tâche traitée. # On met à jour le numéro de la dernière tâche traitée.
last_file = open(last_print_filename, "w") last_file = open(last_print_filename, "w+")
last_file.write(fields[0]) last_file.write(fields[0])
last_file.close() last_file.close()
if fields[3].strip('"') in ["root",'DIRECT PRINT']: if fields[3].strip('"') in ["root",'DIRECT PRINT']:
@ -146,7 +161,7 @@ for item in tasks_to_treat:
if len(jobinfos) <= 2: if len(jobinfos) <= 2:
print "Skipping: %s" % fields[2] print "Skipping: %s" % fields[2]
continue continue
taskID, user, _ = jobinfos taskID, user, filename = jobinfos
user = user.split('@').pop() # On récupère le nom du club si besoin. user = user.split('@').pop() # On récupère le nom du club si besoin.
date = buildDate(fields[5]) date = buildDate(fields[5])
match_taskID = re.compile(r"impression\(%s\)" % taskID) match_taskID = re.compile(r"impression\(%s\)" % taskID)
@ -180,3 +195,6 @@ for item in tasks_to_treat:
else: else:
mail_content = error_mail % (error_send_to, error_send_to, filename, taskID, full_name, user, date, result, u"\n".join(send_to)) mail_content = error_mail % (error_send_to, error_send_to, filename, taskID, full_name, user, date, result, u"\n".join(send_to))
sendMail(error_send_to, error_send_to, mail_content.encode("utf-8")) sendMail(error_send_to, error_send_to, mail_content.encode("utf-8"))
error_file = open(error_filename, "w+")
error_file.close()

31
lib/deprecated.py Normal file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import warnings
import functools
def deprecated(replace=None):
'''This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used.'''
if replace == None:
instead = ""
elif isinstance(replace, str) or isinstance(replace, unicode):
instead = " " + replace
else:
instead = " Use %s instead." % (replace.__name__,)
def real_decorator(func):
"""Nested because a decorator with a parameter has to be coded this way"""
@functools.wraps(func)
def new_func(*args, **kwargs):
warnings.warn_explicit(
"Call to deprecated function %s.%s" % (func.__name__, instead),
category=DeprecationWarning,
filename=func.func_code.co_filename,
lineno=func.func_code.co_firstlineno + 1
)
return func(*args, **kwargs)
return new_func
return real_decorator

44
munin/ipset Executable file
View file

@ -0,0 +1,44 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Compteur des sets ipset
import sys,commands,string
IPSET = "ipset -L "
if sys.argv[0].endswith('macip'):
MACIP = True
else:
MACIP = False
try :
arg = sys.argv[1]
except :
arg = ''
CHAINS = commands.getoutput('%s | grep -- ^Name: | awk \'{print $2}\'' % IPSET).split('\n')
CHAINS = [ chain for chain in CHAINS if (not MACIP and not chain.startswith('MAC-IP')) or ( MACIP and chain.startswith('MAC-IP')) ]
if arg == "config" :
print 'graph_title Ipset' + (MACIP and ' test mac-ip' or '')
print 'graph_args --base 1000 --lower-limit 0'
print 'graph_category network'
print "graph_vlabel nb de regles"
for chain in CHAINS :
nom = string.lower(chain.replace('_', '').replace('-', '').replace('.','').replace('/', ''))
label = chain.replace('_', '-').replace('.','-').replace('/','-')
print "%s.label %s" % (nom, label)
if CHAINS.index(chain) == 0 :
print "%s.draw AREA" % nom
else :
print "%s.draw STACK" % nom
else :
for chain in CHAINS :
nom = string.lower(chain.replace('_', '').replace('-', '').replace('.','').replace('/', ''))
label = chain.replace('_', '-').replace('.','-').replace('/','-')
value = int(commands.getoutput('%s %s | wc -l' % (IPSET, chain))) - 6
print "%s.value %d" % (nom, value)

View file

@ -71,6 +71,9 @@ def do_auth(mac, prise):
or 'autodisc_virus' in m[0].blacklist_actif()): or 'autodisc_virus' in m[0].blacklist_actif()):
return (0, "Bad boy", "isolement") return (0, "Bad boy", "isolement")
if ('carte_etudiant' in m[0].blacklist_actif()):
return (0, "Manque carte etudiant", "accueil")
# Paiement proprio ? # Paiement proprio ?
if not paiement_ok(proprio): if not paiement_ok(proprio):
return (0, "N'a pas payé", "accueil") return (0, "N'a pas payé", "accueil")

View file

@ -126,6 +126,13 @@ def stats(ip_crans=[], ip_ext=[],
# on transforme tout en chaine # on transforme tout en chaine
results = [ [ str(x) for x in line ] for line in results ] results = [ [ str(x) for x in line ] for line in results ]
upload = 0
download = 0
for line in results:
upload+=int(line[4])
download+=int(line[3])
print " upload: %sMo" % (upload/1024/1024)
print " download: %sMo" % (download/1024/1024)
# on modifie les ip en noms de machine et les ports en noms # on modifie les ip en noms de machine et les ports en noms
def nom_de_machine (ip) : def nom_de_machine (ip) :

View file

@ -167,14 +167,15 @@ uploadeurs = curseur.fetchall()
# On regarde s'il y a deux ipv6 identiques avec des mac non identiques # On regarde s'il y a deux ipv6 identiques avec des mac non identiques
collision_mac_ip_request = "SELECT DISTINCT (a.*) FROM mac_ip as a, mac_ip as b where a.ip=b.ip AND a.mac != b.mac AND a.date >= b.date AND a.date - b.date < interval '3 day' ORDER BY a.date;" collision_mac_ip_request = "SELECT DISTINCT a.date as date1, a.mac as mac1, a.ip as ip1, b.date as date2, b.mac as mac2, b.ip as ip2 FROM mac_ip as a, mac_ip as b where a.ip=b.ip AND a.mac != b.mac AND a.date >= b.date AND a.date - b.date < interval '3 day' ORDER BY a.date;"
curseur.execute(collision_mac_ip_request) curseur.execute(collision_mac_ip_request)
collision_mac_ip = curseur.fetchall() collision_mac_ip = curseur.fetchall()
if collision_mac_ip != []: if collision_mac_ip != []:
print "Collision d'addresses ipv6 : " print "Collision d'addresses ipv6 : "
for (date, mac, ip) in collision_mac_ip: for (date1, mac1, ip1, date2, mac2, ip2) in collision_mac_ip:
print "%s %s %s" % (date, ipt.mac_addr(mac), ip) print "%s %s %s" % (date1, ipt.mac_addr(mac1), ip1)
print "%s %s %s" % (date2, ipt.mac_addr(mac2), ip2)
# Table des avertis # Table des avertis
################### ###################
@ -250,7 +251,7 @@ for elupload, eltype, elid in uploadeurs:
# On envoie un mail à disconnect # On envoie un mail à disconnect
################################ ################################
if upload.disconnect_mail_hard: if upload.disconnect_mail_hard:
corps = config.mails.upload.message_disconnect_hard % {'from': upload.expediteur, 'to': upload.expediteur, 'upload': elupload, 'proprio': proprio.Nom(), 'mdc': mdcf, 'chambre': proprio.chbre()} corps = config.mails.upload.message_disconnect_hard % {'from': upload.expediteur, 'to': upload.expediteur, 'upload': elupload, 'proprio': proprio.Nom(), 'mdc': mdcf, 'chambre': proprio.chbre(), 'aid':proprio.id()}
corps = corps.encode('utf-8') corps = corps.encode('utf-8')
mail.sendmail(upload.expediteur, upload.expediteur, corps) mail.sendmail(upload.expediteur, upload.expediteur, corps)
@ -311,7 +312,7 @@ for elupload, eltype, elid in uploadeurs:
mail.sendmail(upload.expediteur, upload.expediteur, corps) mail.sendmail(upload.expediteur, upload.expediteur, corps)
# On supprime les vieux avertisements # On supprime les vieux avertisements
curseur.execute("DELETE FROM avertis_upload_hard WHERE date < timestamp 'now' - interval '1 day'") curseur.execute("DELETE FROM avertis_upload_hard WHERE date < timestamp 'now' - interval '85200 seconds'") # 23h et 40min pour prolonger les blacklists toujours au dessus de la limite
curseur.execute("DELETE FROM avertis_upload_soft WHERE date < timestamp 'now' - interval '1 day'") curseur.execute("DELETE FROM avertis_upload_soft WHERE date < timestamp 'now' - interval '1 day'")
################################################################################ ################################################################################

View file

@ -137,7 +137,7 @@ Subject: %(subject)s
Content-Type: multipart/mixed; boundary="_424234545aaff-ffca234efff-556adceff5646_" Content-Type: multipart/mixed; boundary="_424234545aaff-ffca234efff-556adceff5646_"
--_424234545aaff-ffca234efff-556adceff5646_ --_424234545aaff-ffca234efff-556adceff5646_
Content-Type: text/plain, charset="UTF-8" Content-Type: text/plain; charset="UTF-8"
%(contenu)s %(contenu)s

View file

@ -98,7 +98,7 @@ if __name__ == '__main__':
message = """From: %(from)s message = """From: %(from)s
To: %(to)s To: %(to)s
Subject: %(subject)s Subject: %(subject)s
Content-Type: text/plain, charset="UTF-8" Content-Type: text/plain; charset="UTF-8"
%(contenu)s %(contenu)s

View file

@ -4,15 +4,19 @@
-- effacement des vieux enregistrements -- effacement des vieux enregistrements
DELETE FROM upload where date< timestamp 'now' - interval '2 days'; DELETE FROM upload where date< timestamp 'now' - interval '2 days';
-- la même pour upload6
DELETE FROM upload6 WHERE date< timestamp 'now' - interval '2 days';
-- On ne blackliste plus pour virus, on droppe seulement -- On ne blackliste plus pour virus, on droppe seulement
-- DELETE FROM virus where date< timestamp 'now' - interval '2 days'; -- DELETE FROM virus where date< timestamp 'now' - interval '2 days';
DELETE FROM flood where date< timestamp 'now' - interval '2 days'; -- Idem pour flood
-- DELETE FROM flood where date< timestamp 'now' - interval '2 days';
-- suppression complète des entrées -- suppression complète des entrées
VACUUM; VACUUM;
-- réindexation des tables -- réindexation des tables
REINDEX TABLE upload; REINDEX TABLE upload;
REINDEX TABLE virus; REINDEX TABLE upload6;
-- REINDEX TABLE virus;
-- REINDEX TABLE flood; -- flood n'a pas d'index -- REINDEX TABLE flood; -- flood n'a pas d'index
REINDEX TABLE p2p; REINDEX TABLE p2p;

0
utils/__init__.py Normal file
View file

View file

@ -2,7 +2,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# check_cert.py -- Petit mail de vérification du certificat d'un serveur # check_cert.py -- Petit mail de vérification du certificat d'un serveur
# ce script vérifie principalement la date # ce script vérifie principalement la date d'expiration et envoie un mail
# d'avertissement si celle-ci est proche (paramétrable)
# #
# Copyright (c) 2013 Daniel STAN # Copyright (c) 2013 Daniel STAN
# Authors: Daniel STAN <daniel.stan@crans.org> # Authors: Daniel STAN <daniel.stan@crans.org>
@ -20,7 +21,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from M2Crypto import SSL from M2Crypto import SSL
from M2Crypto import X509
import datetime import datetime
import sys import sys
@ -31,8 +34,9 @@ import smtplib
# #
# Config ! # Config !
# #
host = 'webmail.crans.org' host = 'localhost'
port = 443 port = 443
filename = False # if True, port ignored and host is in fact a path
# afficher la sortie plutôt que l'envoyer: # afficher la sortie plutôt que l'envoyer:
verb = False verb = False
# delai d'avertissement # delai d'avertissement
@ -42,46 +46,60 @@ delay = datetime.timedelta(days=15)
mail_src = 'root@crans.org' mail_src = 'root@crans.org'
mail_dest = "roots@crans.org" mail_dest = "roots@crans.org"
mail_host = 'localhost' mail_host = 'localhost'
#
# Argument parsing !
#
# TODO argparse + doc
for arg in sys.argv[1:]: for arg in sys.argv[1:]:
if arg == '-v': if arg == '-v':
verb = True verb = True
continue continue
if arg == '--filename':
filename = True
try: try:
port = int(arg) port = int(arg)
except ValueError: except ValueError:
host = arg host = arg
# TODO: permettre la vérification directement sur un fichier #
# get cert: # Getting cert !
conn = SSL.Connection(SSL.Context()) #
try: if filename:
conn.connect((host, port)) cert = X509.load_cert(host)
except SSL.Checker.WrongHost: else:
if host != 'localhost': conn = SSL.Connection(SSL.Context())
raise try:
conn.connect((host, port))
except SSL.Checker.WrongHost:
if host != 'localhost':
raise
cert = conn.get_peer_cert() cert = conn.get_peer_cert()
conn.close() conn.close()
#
# Real computation (woah !)
#
expire_date = cert.get_not_after().get_datetime() expire_date = cert.get_not_after().get_datetime()
now = datetime.datetime.now(expire_date.tzinfo) now = datetime.datetime.now(expire_date.tzinfo)
if now + delay > expire_date: if now + delay > expire_date or verb:
subject = cert.get_subject().as_text() subject = cert.get_subject().as_text()
short_sub = subject short_sub = subject
try: try:
subject += "(alt: %s)" % cert.get_ext('subjectAltName').get_value() subject += "(alt: %s)" % cert.get_ext('subjectAltName').get_value()
except LookupError: except LookupError:
pass pass
conn = smtplib.SMTP(mail_host)
msg = MIMEText(u"""Attention, le certificat suivant arrive bientôt à expiration :\n%s\n msg = MIMEText(u"""Attention, le certificat suivant arrive bientôt à expiration :\n%s\n
Temps avant expiration: %s""" % (subject,(expire_date - now)), _charset="utf-8") Temps avant expiration: %s""" % (subject,(expire_date - now)), _charset="utf-8")
msg['From'] = mail_src msg['From'] = mail_src
msg['To'] = mail_dest msg['To'] = mail_dest
msg['Subject'] = u"Expiration imminente du certificat %s" % short_sub msg['Subject'] = u"Expiration imminente du certificat %s" % short_sub
if not verb: if not verb:
conn = smtplib.SMTP(mail_host)
conn.sendmail(mail_src, mail_dest, msg.as_string()) conn.sendmail(mail_src, mail_dest, msg.as_string())
conn.quit()
else: else:
print msg.as_string() print msg.get_payload(decode=True)
conn.quit()

View file

@ -8,7 +8,7 @@ TEMPFILE=`tempfile`
# on évite de casser le dépôt darcs # on évite de casser le dépôt darcs
umask 002 umask 002
wget -o /dev/null -O $TEMPFILE http://standards.ieee.org/regauth/oui/oui.txt \ wget -o /dev/null -O $TEMPFILE http://standards.ieee.org/regauth/oui/oui.txt \
&& awk -F '[\t ]*(hex)[ \t]*' '(/(hex)/) {gsub("-",":",$1) ; print $1" "$2}' < $TEMPFILE > /usr/scripts/gestion/ethercodes.dat \ && awk -F '[\t ]*(hex)[ \t]*' '(/(hex)/) {gsub("-",":",$1) ; {gsub("^ *", "", $1)}; {gsub("\\(", "", $1)}; {gsub("\\)", "", $2)}; print $1" "$2}' < $TEMPFILE > /usr/scripts/gestion/ethercodes.dat \
&& cd /usr/scripts/gestion \ && cd /usr/scripts/gestion \
&& git commit --author="Cron Daemon <root@crans.org>" -m "[ethercodes.dat] Mise à jour du fichier vendeur" ethercodes.dat > /dev/null \ && git commit --author="Cron Daemon <root@crans.org>" -m "[ethercodes.dat] Mise à jour du fichier vendeur" ethercodes.dat > /dev/null \
&& git push > /dev/null && git push > /dev/null

View file

@ -3,17 +3,16 @@
import os import os
import PagesPerso import PagesPerso
def comptes(): class ClubList(PagesPerso.AccountList):
"""Retourne la liste des comptes""" home = "/home/club"
return filter(lambda x: os.path.isdir(u"/home/club/%s" % x) and not os.path.islink(u"/home/club/%s" % x), www = ""
os.listdir(u"/home/club")) url = "http://clubs.ens-cachan.fr/%s/"
def url(self): def comptes(self):
"""URL vers la page perso""" """Retourne la liste des comptes"""
return u"http://clubs.ens-cachan.fr/%s/" % self.login return filter(lambda x: os.path.isdir(u"/home/club/%s" % x) and not os.path.islink(u"/home/club/%s" % x),
os.listdir(u"/home/club"))
def execute(macro, args):
return macro.formatter.rawHTML(ClubList().to_html())
PagesPerso.comptes = comptes
PagesPerso.account.home = "/home/club"
PagesPerso.account.www = ""
PagesPerso.account.url = url
execute = PagesPerso.execute

View file

@ -2,16 +2,57 @@
import os import os
class account: class AccountList:
"""Classe représentant la page perso d'une personne"""
home = "/home" home = "/home"
www = "/www" www = "/www"
url = "http://perso.crans.org/%s/"
def __init__(self, login): def __init__(self):
return
def comptes(self):
"""Retourne la liste des comptes"""
return filter(lambda x: os.path.isdir(u"/home/%s/www" % x) and not os.path.islink(u"/home/%s/www" % x),
os.listdir(u"/home/mail"))
def makeAnchor(self,letter):
return u"<div class=\"vignetteperso\"><a class=\"letter_anchor\" name=\"index_%s\"><span>%s:</span></a></div>" % ( letter, letter )
def makeIndex(self,letter_list):
index = u''
for aLetter in letter_list:
index = u"%s<a href=\"#index_%s\">%s</a>" % ( index, aLetter, aLetter)
return u"<div class=\"alphabetic_index\">%s</div>" % index
def to_html(self):
dirs = self.comptes()
dirs.sort()
html = u""
premiere_lettre = ''
letter_list = []
for d in dirs:
if premiere_lettre != d[0]:
premiere_lettre = d[0]
letter_list.append(premiere_lettre)
html = u"%s\n%s" % ( html, self.makeAnchor(premiere_lettre) )
html = u"%s\n%s" % (html, Account(self.home, d, self.www, self.url).to_html())
index = self.makeIndex(letter_list)
html = index + html
html += u'<br style="clear: both">'
return html
class Account:
"""Classe représentant la page perso d'une personne"""
def __init__(self, home, login, www, url):
"""Instanciation avec le `login' de la personne""" """Instanciation avec le `login' de la personne"""
self.login = login self.login = login
self.home = "%s/%s" % (self.home, login) self.home = "%s/%s" % (home, login)
self.www = www
self.url = url
_info = None _info = None
def info(self, champ): def info(self, champ):
@ -39,10 +80,6 @@ class account:
"""Chemin vers le www""" """Chemin vers le www"""
return u"%s%s" % (self.home, self.www) return u"%s%s" % (self.home, self.www)
def url(self):
"""URL vers la page perso"""
return u"http://perso.crans.org/%s/" % self.login
def logo(self): def logo(self):
"""URL du logo s'il y en a un""" """URL du logo s'il y en a un"""
if self.info("logo"): if self.info("logo"):
@ -52,13 +89,13 @@ class account:
else: else:
logo = self.info("logo") logo = self.info("logo")
if os.path.isfile("%s/%s" % (self.chemin(), logo)): if os.path.isfile("%s/%s" % (self.chemin(), logo)):
return u"%s%s" % (self.url(), logo) return u"%s%s" % (self.url % self.login, logo)
return u"http://perso.crans.org/pageperso.png" return u"http://perso.crans.org/pageperso.png"
def __str__(self): def to_html(self):
"""Renvoie le code HTML correspondant au fichier .info""" """Renvoie le code HTML correspondant au fichier .info"""
html = [ u'<div class="vignetteperso">', html = [ u'<div class="vignetteperso">',
u'<a href="%s">' % self.url(), u'<a href="%s">' % (self.url % self.login),
u'<img src="%s" alt="%s">' % (self.logo(), self.login), u'<img src="%s" alt="%s">' % (self.logo(), self.login),
u'</a><br>', u'</a><br>',
self.info("nom") and u'<b>%s</b><br>' % self.info("nom") or u'%s<br>' % self.login, self.info("nom") and u'<b>%s</b><br>' % self.info("nom") or u'%s<br>' % self.login,
@ -66,38 +103,6 @@ class account:
u'</div>' ] u'</div>' ]
return u'\n'.join(html) return u'\n'.join(html)
def comptes():
"""Retourne la liste des comptes"""
return filter(lambda x: os.path.isdir(u"/home/%s/www" % x) and not os.path.islink(u"/home/%s/www" % x),
os.listdir(u"/home/mail"))
def makeAnchor(letter):
return u"<div class=\"vignetteperso\"><a class=\"letter_anchor\" name=\"index_%s\"><span>%s:</span></a></div>" % ( letter, letter )
def makeIndex(letter_list):
index = u''
for aLetter in letter_list:
index = u"%s<a href=\"#index_%s\">%s</a>" % ( index, aLetter, aLetter)
return u"<div class=\"alphabetic_index\">%s</div>" % index
def execute(macro, args): def execute(macro, args):
dirs = comptes() return macro.formatter.rawHTML(AccountList().to_html())
dirs.sort()
html = u""
premiere_lettre = ''
letter_list = []
for d in dirs:
if premiere_lettre != d[0]:
premiere_lettre = d[0]
letter_list.append(premiere_lettre)
html = u"%s\n%s" % ( html, makeAnchor(premiere_lettre) )
html = u"%s\n%s" % (html, account(d).__str__())
index = makeIndex(letter_list)
html = index + html
html += u'<br style="clear: both">'
return macro.formatter.rawHTML(html)

View file

@ -33,9 +33,10 @@ class Theme(ThemeBase):
(u'http://www.mozilla-europe.org/fr/firefox/', (u'http://www.mozilla-europe.org/fr/firefox/',
u'badges_80x15_firefox.gif', u'Get firefox'), u'badges_80x15_firefox.gif', u'Get firefox'),
(u'http://www.debian.org/', u'badges_80x15_debian.png', u'Debian powered'), (u'http://www.debian.org/', u'badges_80x15_debian.png', u'Debian powered'),
(u'http://www.apache.org/', u'badges_80x15_apache.gif', u'Apache powered'), (u'http://wiki.nginx.org/', u'badges_80x15_nginx.png', u'Nginx powered'),
(u'http://www.python.org/', u'badges_80x15_python.png', u'Python powered'), (u'http://www.python.org/', u'badges_80x15_python.png', u'Python powered'),
(u'http://www.federez.org/', u'badges_80x15_federez.png', u'Membre du r&eacute;seau federez'), (u'http://www.federez.org/', u'badges_80x15_federez.png', u'Membre du r&eacute;seau federez'),
(u'/VieCrans/Donateurs', u'badges_80x15_donor.png', u'Généreux donateurs'),
(u'http://moinmo.in/', u'badges_80x15_moinmoin.png', u'Moinmoin powered'), (u'http://moinmo.in/', u'badges_80x15_moinmoin.png', u'Moinmoin powered'),
(u'http://jigsaw.w3.org/css-validator/check?uri=referer&amp;profile=css3&amp;warning=no', (u'http://jigsaw.w3.org/css-validator/check?uri=referer&amp;profile=css3&amp;warning=no',
u'valid_css_80x15.png', u'Valid css3'), u'valid_css_80x15.png', u'Valid css3'),