From ad335866ea1bb98dc6ce6d55aed54a4ce14db3ae Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Tue, 18 Feb 2014 12:06:26 +0100
Subject: [PATCH 01/52] digicode: secrets_new est dans gestion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Si ça fonctionnait jusque là , c'est qu'il doit se passer des trucs crades
avec le sys.path dans les scripts qui importent ce fichier.
---
impression/digicode.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/impression/digicode.py b/impression/digicode.py
index 486ff6ef..0275496f 100644
--- a/impression/digicode.py
+++ b/impression/digicode.py
@@ -33,9 +33,10 @@ import commands
import string
import random
import requests
-sys.path.append("/usr/scripts/")
+if not '/usr/scripts' in sys.path:
+ sys.path.append("/usr/scripts")
import cranslib.utils.files
-import secrets_new
+import gestion.secrets_new as secrets_new
digicode_pass = secrets_new.get("digicode_pass")
# #############################################################
From 63895c98d4659c9753ecab280cbae235e509e9b0 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Tue, 18 Feb 2014 21:36:52 +0100
Subject: [PATCH 02/52] =?UTF-8?q?[populate=5FsshFingerprint]=20Ne=20pas=20?=
=?UTF-8?q?pr=C3=A9suposer=20que=20la=20valeur=20d'un=20attribut=20est=20u?=
=?UTF-8?q?ne=20string?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/populate_sshFingerprint.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gestion/gen_confs/populate_sshFingerprint.py b/gestion/gen_confs/populate_sshFingerprint.py
index ac146504..3b32d4b4 100755
--- a/gestion/gen_confs/populate_sshFingerprint.py
+++ b/gestion/gen_confs/populate_sshFingerprint.py
@@ -85,7 +85,7 @@ def publish_keys():
validation=check_keys(keys)
machines=get_machines()
for machine in machines:
- sshkeys_old=[key.value for key in machine.get('sshFingerprint',[])]
+ sshkeys_old=[str(key) for key in machine.get('sshFingerprint',[])]
sshkeys_new=[key.decode('UTF-8') for algo,key in keys.items() if validation[algo]]
if not set(sshkeys_old)==set(sshkeys_new):
machine['sshFingerprint']=sshkeys_new
From cd8ce5c7294cc78fb2d421dbf75cb00705f05b98 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Wed, 19 Feb 2014 19:35:57 +0100
Subject: [PATCH 03/52] [base, komaz, utils, zamok] Factorisation de code via
l'ajout de la methode blacklisted_ips
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
De plus, on rend le code plus jolie en prenant en compte l'ajout récent de méthodes dans
lc_ldap.
---
gestion/gen_confs/firewall4/base.py | 13 ++---------
gestion/gen_confs/firewall4/komaz.py | 32 +++++++---------------------
gestion/gen_confs/firewall4/utils.py | 27 +++++++++++++++++++++--
gestion/gen_confs/firewall4/zamok.py | 4 ++--
4 files changed, 37 insertions(+), 39 deletions(-)
diff --git a/gestion/gen_confs/firewall4/base.py b/gestion/gen_confs/firewall4/base.py
index d98f5f54..9962ac8b 100644
--- a/gestion/gen_confs/firewall4/base.py
+++ b/gestion/gen_confs/firewall4/base.py
@@ -3,7 +3,6 @@
import os
import sys
import socket
-import netaddr
import utils
from utils import pretty_print, anim, OK, cprint
@@ -96,7 +95,7 @@ class firewall(utils.firewall_tools) :
# for ip in ip_list:
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
# # Est-ce qu'il y a des blacklists hard parmis les blacklists de la machine
-# if machine and set([bl.value['type'] for bl in machine[0].blacklist_actif() ]).intersection(config.blacklist_sanctions):
+# if machine and set([bl['type'] for bl in machine[0].blacklist_actif() ]).intersection(config.blacklist_sanctions):
# try: self.ipset['blacklist']['hard'].add(ip)
# except IpsetError: pass
# else:
@@ -112,15 +111,7 @@ class firewall(utils.firewall_tools) :
if fill_ipset:
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
# On récupère la liste de toutes les ips blacklistés hard
- bl_hard_ips = set(
- str(ip) for ips in
- [
- machine['ipHostNumber'] for machine in self.blacklisted_machines() if machine['ipHostNumber'] and reduce(lambda x,y: x or y, ( ip.value in netaddr.IPNetwork(n) for n in config.NETs['all'] for ip in machine['ipHostNumber']))
- if set([bl.value['type'] for bl in machine.blacklist_actif() ]).intersection(config.blacklist_sanctions)
- ]
- for ip in ips
- )
-
+ bl_hard_ips = self.blacklisted_ips(config.blacklist_sanctions, config.NETs['all'])
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
print OK
diff --git a/gestion/gen_confs/firewall4/komaz.py b/gestion/gen_confs/firewall4/komaz.py
index e1104e3d..da380759 100644
--- a/gestion/gen_confs/firewall4/komaz.py
+++ b/gestion/gen_confs/firewall4/komaz.py
@@ -298,7 +298,7 @@ class firewall(base.firewall_routeur):
# for ip in ip_list:
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
# # Est-ce qu'il y a des blacklists soft parmis les blacklists de la machine
-# if machine and set([bl.value['type'] for bl in machine[0].blacklist_actif() ]).intersection(base.config.blacklist_sanctions_soft):
+# if machine and set([bl['type'] for bl in machine[0].blacklist_actif() ]).intersection(base.config.blacklist_sanctions_soft):
# try: self.ipset['blacklist']['soft'].add(ip)
# except IpsetError: pass
# else:
@@ -312,15 +312,7 @@ class firewall(base.firewall_routeur):
if fill_ipset:
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
# On récupère la liste de toutes les ips blacklistés soft
- bl_soft_ips = set(
- str(ip) for ips in
- [
- machine['ipHostNumber'] for machine in self.blacklisted_machines() if machine['ipHostNumber'] and reduce(lambda x,y: x or y, ( ip.value in base.netaddr.IPNetwork(n) for n in base.config.NETs['all'] for ip in machine['ipHostNumber']))
- if set([bl.value['type'] for bl in machine.blacklist_actif() ]).intersection(base.config.blacklist_sanctions_soft)
- ]
- for ip in ips
- )
-
+ bl_soft_ips = self.blacklisted_ips(base.config.blacklist_sanctions_soft, base.config.NETs['all'])
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
print OK
@@ -348,7 +340,7 @@ class firewall(base.firewall_routeur):
# for ip in ip_list:
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
# # Est-ce qu'il y a des blacklists pour upload parmis les blacklists de la machine
-# if machine and set([bl.value['type'] for bl in machine[0].blacklist_actif() ]).intersection(blacklist_bridage_upload):
+# if machine and set([bl['type'] for bl in machine[0].blacklist_actif() ]).intersection(blacklist_bridage_upload):
# try: self.ipset['blacklist']['upload'].add(ip)
# except IpsetError: pass
# else:
@@ -362,15 +354,7 @@ class firewall(base.firewall_routeur):
if fill_ipset:
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['upload'])
# On récupère la liste de toutes les ips blacklistés pour upload
- bl_upload_ips = set(
- str(ip) for ips in
- [
- machine['ipHostNumber'] for machine in self.blacklisted_machines()
- if set([bl.value['type'] for bl in machine.blacklist_actif() ]).intersection(base.config.blacklist_bridage_upload)
- ]
- for ip in ips
- )
-
+ bl_upload_ips = self.blacklisted_ips(base.config.blacklist_bridage_upload, base.config.NETs['all'])
self.ipset['blacklist']['upload'].restore(bl_upload_ips)
print OK
@@ -446,13 +430,13 @@ class firewall(base.firewall_routeur):
for machine in self.machines():
for ip in machine['ipHostNumber']:
- if 'portTCPout' in machine.attrs.keys():
+ if 'portTCPout' in machine:
add_ports(ip, machine, 'tcp', 'out')
- if 'portUDPout' in machine.attrs.keys():
+ if 'portUDPout' in machine:
add_ports(ip, machine, 'udp', 'out')
- if 'portTCPin' in machine.attrs.keys():
+ if 'portTCPin' in machine:
add_ports(ip, machine, 'tcp', 'in')
- if 'portUDPin' in machine.attrs.keys():
+ if 'portUDPin' in machine:
add_ports(ip, machine, 'udp', 'in')
self.add(table, chain, '-j REJECT')
diff --git a/gestion/gen_confs/firewall4/utils.py b/gestion/gen_confs/firewall4/utils.py
index a2f84514..7e49198b 100644
--- a/gestion/gen_confs/firewall4/utils.py
+++ b/gestion/gen_confs/firewall4/utils.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
import os
import sys
+import netaddr
if '/usr/scripts/' not in sys.path:
sys.path.append('/usr/scripts/')
@@ -58,11 +59,19 @@ class firewall_tools(object) :
"""Renvois la liste de toutes les machines"""
if self._machines:
return self._machines
+ # On utilise allMachinesAdherents car on a besoin que
+ # les machine.proprio() soit déjà peuplés. En effet, on regarde
+ # les blacklistes d'un proprio lorsque l'on regarde les blacklistes
+ # d'une machine
self._machines, self._adherents = self.conn.allMachinesAdherents()
+ self._adherents = [ adh for adh in self._adherents if adh.paiement_ok() ]
return self._machines
def adherents(self):
- """Renvois la liste de tous les adhérents"""
+ """
+ Renvois la liste de tous les adhérents à jour de paiement
+ (car on suppose que la blackliste paiement est hard)
+ """
if self._adherents:
return self._adherents
self._machines, self._adherents = self.conn.allMachinesAdherents()
@@ -76,8 +85,22 @@ class firewall_tools(object) :
self._blacklisted_machines = [ machine for machine in self.machines() if machine.blacklist_actif() ]
return self._blacklisted_machines
+ def blacklisted_ips(self, blacklist_sanctions=None, nets=None):
+ """Renvois l'ensemble des ips des machines ayant une blacklist dans blacklist_sanctions et étant dans nets si spécifié"""
+ bl_ips = set()
+ for machine in self.blacklisted_machines():
+ if blacklist_sanctions is None or set(bl['type'] for bl in machine.blacklist_actif()).intersection(blacklist_sanctions):
+ for ip in machine['ipHostNumber']:
+ if nets is None:
+ bl_ips.add(str(ip))
+ else:
+ for net in nets:
+ if ip in netaddr.IPNetwork(net):
+ bl_ips.add(str(ip))
+ return bl_ips
+
def blacklisted_adherents(self, excepts=[]):
- """Renvois la liste de tous les adhérents ayant une blackliste active"""
+ """Renvois la liste de tous les adhérents ayant une blackliste active en ignorant les blacklist de excepts"""
if self._blacklisted_adherents and self._blacklisted_adherents_type == set(excepts):
return self._blacklisted_adherents
self._blacklisted_adherents = filter(lambda adh: adh.blacklist_actif(excepts), self.adherents())
diff --git a/gestion/gen_confs/firewall4/zamok.py b/gestion/gen_confs/firewall4/zamok.py
index 1413602e..e3f0796d 100644
--- a/gestion/gen_confs/firewall4/zamok.py
+++ b/gestion/gen_confs/firewall4/zamok.py
@@ -102,8 +102,8 @@ class firewall(base.firewall):
self.add(table, chain, '-d 127.0.0.1/8 -j RETURN')
for net in base.config.NETs['all']:
self.add(table, chain, '-d %s -j RETURN' % net)
- for adh in self.blacklisted_adherents(['paiement']):
- if 'uidNumber' in adh.attrs.keys():
+ for adh in self.blacklisted_adherents():
+ if 'uidNumber' in adh:
self.add(table, chain, '-m owner --uid-owner %s -j REJECT' % adh['uidNumber'][0])
print OK
From aeb8b55ce12917a4d8ca76b96c57a9498c23a125 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Wed, 19 Feb 2014 19:38:11 +0100
Subject: [PATCH 04/52] [whos_lc] On lit de l'utf8 sur arguments
---
gestion/whos_lc.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gestion/whos_lc.py b/gestion/whos_lc.py
index 7c5107ae..9ad86e50 100755
--- a/gestion/whos_lc.py
+++ b/gestion/whos_lc.py
@@ -9,7 +9,7 @@ import lc_ldap.filter2 as filter
if __name__ == '__main__':
if len(sys.argv) >1:
conn=lc_ldap.shortcuts.lc_ldap_admin()
- result=conn.search(filter.human_to_ldap(sys.argv[1]), sizelimit=4000)
+ result=conn.search(filter.human_to_ldap(sys.argv[1].decode('utf-8')), sizelimit=4000)
if not result:
print "rien trouvé"
else:
From 470fa70f1433be526cc2abe2b65cc9ec9a593ff9 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Fri, 21 Feb 2014 14:49:15 +0100
Subject: [PATCH 05/52] =?UTF-8?q?[generate]=20Une=20fonction=20pour=20trig?=
=?UTF-8?q?ger=20generate=20sur=20un=20h=C3=B4te=20distant?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Lève une exception si une quelconque erreure arrive.
---
gestion/gen_confs/generate.py | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/gestion/gen_confs/generate.py b/gestion/gen_confs/generate.py
index 033614bd..5709b7e7 100755
--- a/gestion/gen_confs/generate.py
+++ b/gestion/gen_confs/generate.py
@@ -15,7 +15,7 @@ arguments peuvent être founis pour une même option, les séparer par &
"""
import sys, signal, os, getopt
-
+import subprocess
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, hostname
@@ -33,6 +33,22 @@ signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
db = crans_ldap()
make_lock('auto_generate', 'Big lock', nowait=1)
+def trigger(host):
+ if not 'adm.crans.org' in host:
+ host=host + '.adm.crans.org'
+ options = ['PasswordAuthentication=no', 'ConnectTimeout=1', 'VerifyHostKeyDNS=yes',
+ 'BatchMode=yes', 'ServerAliveInterval=5', 'ServerAliveCountMax=1']
+ args = ["ssh", "-4", "-i", "/etc/crans/secrets/trigger-generate" ]
+ for opt in options:
+ args.append('-o')
+ args.append(opt)
+ args.extend(["rpcssh@%s" % host, "generate"])
+ p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ if err:
+ raise Exception(err)
+ return out
+
class base_reconfigure:
try:
sys.path.append('/etc/crans/')
From e579798fdcf402e77ef883a9ad06eab91efea0f6 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Fri, 21 Feb 2014 18:05:02 +0100
Subject: [PATCH 06/52] =?UTF-8?q?[gen=5Fconfs/bind]=20Dans=20la=20m=C3=A9t?=
=?UTF-8?q?hode=20add=5Fsshfp=5Frecord,=20on=20rattrape=20les=20exceptions?=
=?UTF-8?q?=20du=20=C3=A0=20des=20sshFingerprint=20mal=20form=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/bind.py | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/gestion/gen_confs/bind.py b/gestion/gen_confs/bind.py
index 4335ba72..e929abd2 100755
--- a/gestion/gen_confs/bind.py
+++ b/gestion/gen_confs/bind.py
@@ -254,17 +254,22 @@ class Zone(ZoneBase):
def add_sshfp_record(self, nom, machine):
for sshkey in machine.get('sshFingerprint', []):
- algo_txt, key = str(sshkey).split()[:2]
- algo=config.sshfs_ralgo[algo_txt][1]
- for hash in config.sshfp_hash.keys():
- self.add(SSHFP(nom, hash, algo, key))
- if self.ipv4 and self.ipv6:
- if nom == '@':
- self.add(SSHFP("v4", hash, algo, key))
- self.add(SSHFP("v6", hash, algo, key))
- else:
- self.add(SSHFP("%s.v4" % nom, hash, algo, key))
- self.add(SSHFP("%s.v6" % nom, hash, algo, key))
+ try:
+ algo_txt, key = str(sshkey).split()[:2]
+ algo=config.sshfs_ralgo[algo_txt][1]
+ for hash in config.sshfp_hash.keys():
+ self.add(SSHFP(nom, hash, algo, key))
+ if self.ipv4 and self.ipv6:
+ if nom == '@':
+ self.add(SSHFP("v4", hash, algo, key))
+ self.add(SSHFP("v6", hash, algo, key))
+ else:
+ self.add(SSHFP("%s.v4" % nom, hash, algo, key))
+ self.add(SSHFP("%s.v6" % nom, hash, algo, key))
+ # KeyError is l'algo dans ldap n'est pas connu
+ # TypeError si la clef n'est pas bien en base64
+ except (KeyError, TypeError):
+ pass
def add_machine(self, machine):
for host in machine['host']:
From 8a07512ee60a8e78cfc6259de5c7f06fcb1d904c Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Fri, 21 Feb 2014 18:06:13 +0100
Subject: [PATCH 07/52] [gen_confs/bind] Ajout d'un record TLSA pour
https://lists.crans.org/
---
gestion/gen_confs/bind.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/gestion/gen_confs/bind.py b/gestion/gen_confs/bind.py
index e929abd2..1508e05d 100755
--- a/gestion/gen_confs/bind.py
+++ b/gestion/gen_confs/bind.py
@@ -478,6 +478,7 @@ class dns(gen_config) :
TLSA('nagios.crans.org.', 443, 'tcp', None, 3, 2),
TLSA('pad.crans.org.', 443, 'tcp', None, 3, 2),
TLSA('news.crans.org.', 443, 'tcp', None, 3, 2),
+ TLSA('lists.crans.org.', 443, 'tcp', None, 3, 2),
TLSA('asterisk.crans.org.', 5061, 'tcp', None, 3, 2),
TLSA('smtp.crans.org.', 465, 'tcp', None, 3, 2),
TLSA('imap.crans.org.', 993, 'tcp', None, 3, 2),
From da2274874e0e9eefd776cff3cc45e4e5091e0646 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Fri, 21 Feb 2014 19:42:05 +0100
Subject: [PATCH 08/52] mail convocation ago
---
gestion/mail/convocation_ago.py | 52 ++++++++++++++++++++++++
gestion/mail/template/ago/From/fr | 1 +
gestion/mail/template/ago/Subject/fr | 1 +
gestion/mail/template/ago/To/fr | 1 +
gestion/mail/template/ago/body/ATTENTION | 3 ++
gestion/mail/template/ago/body/en.md | 37 +++++++++++++++++
gestion/mail/template/ago/body/fr.md | 45 ++++++++++++++++++++
7 files changed, 140 insertions(+)
create mode 100755 gestion/mail/convocation_ago.py
create mode 100644 gestion/mail/template/ago/From/fr
create mode 100644 gestion/mail/template/ago/Subject/fr
create mode 100644 gestion/mail/template/ago/To/fr
create mode 100644 gestion/mail/template/ago/body/ATTENTION
create mode 100644 gestion/mail/template/ago/body/en.md
create mode 100644 gestion/mail/template/ago/body/fr.md
diff --git a/gestion/mail/convocation_ago.py b/gestion/mail/convocation_ago.py
new file mode 100755
index 00000000..e45cd5d5
--- /dev/null
+++ b/gestion/mail/convocation_ago.py
@@ -0,0 +1,52 @@
+#!/bin/bash /usr/scripts/python.sh
+# -*- coding: utf-8 -*-
+
+import sys
+import smtplib
+from gestion import config
+from gestion.affich_tools import cprint
+from gestion import mail
+import lc_ldap.shortcuts
+from utils.sendmail import actually_sendmail
+
+# Attention, si à True envoie effectivement les mails
+SEND=('--do-it' in sys.argv)
+# Prévisualisation
+PREV=('--prev' in sys.argv)
+
+ldap_filter=u"(&(paiement=%(annee)s)(aid=*))" % {'annee': config.ann_scol}
+#ldap_filter=u"(|(uid=dstan)(uid=lasseri))"
+
+conn=lc_ldap.shortcuts.lc_ldap_readonly()
+mailaddrs=set()
+for adh in conn.search(ldap_filter, sizelimit=2000):
+ if 'canonicalAlias' in adh.attrs.keys():
+ mailaddrs.add(str(adh['canonicalAlias'][0]))
+ elif 'mail' in adh.attrs.keys():
+ mailaddrs.add(str(adh['mail'][0]))
+ elif 'uid' in adh.attrs.keys():
+ mailaddrs.add(str(adh['uid'][0]) + '@crans.org')
+ else:
+ raise ValueError("%r has nor mail nor canonicalAlias, only %s" % (adh, adh.attrs.keys()))
+
+echecs=[]
+From = 'ca@crans.org'
+for To in mailaddrs:
+ cprint(u"Envoi du mail à %s" % To)
+ mailtxt=mail.generate('ago', {'To':To, 'From': From})
+ if PREV:
+ print mailtxt.as_string()
+ try:
+ if SEND:
+ actually_sendmail('ca@crans.org', (To,), mailtxt)
+ cprint(" Envoyé !")
+ else:
+ cprint(" (simulé)")
+ except:
+ cprint(u"Erreur lors de l'envoi à %s " % To, "rouge")
+ echecs.append(To)
+
+
+if echecs:
+ print "\nIl y a eu des erreurs :"
+ print echecs
diff --git a/gestion/mail/template/ago/From/fr b/gestion/mail/template/ago/From/fr
new file mode 100644
index 00000000..2510ed39
--- /dev/null
+++ b/gestion/mail/template/ago/From/fr
@@ -0,0 +1 @@
+Le CA du Crans <{{From}}>
diff --git a/gestion/mail/template/ago/Subject/fr b/gestion/mail/template/ago/Subject/fr
new file mode 100644
index 00000000..00799112
--- /dev/null
+++ b/gestion/mail/template/ago/Subject/fr
@@ -0,0 +1 @@
+[Crans] Convocation à l'Assemblée Générale Ordinaire de l'association
diff --git a/gestion/mail/template/ago/To/fr b/gestion/mail/template/ago/To/fr
new file mode 100644
index 00000000..38476730
--- /dev/null
+++ b/gestion/mail/template/ago/To/fr
@@ -0,0 +1 @@
+{{To}}
diff --git a/gestion/mail/template/ago/body/ATTENTION b/gestion/mail/template/ago/body/ATTENTION
new file mode 100644
index 00000000..1344cdb0
--- /dev/null
+++ b/gestion/mail/template/ago/body/ATTENTION
@@ -0,0 +1,3 @@
+Le corps des messages est rédigé en markdown
+cd http://tmpvar.com/markdown.html pour un aperçu
+du rendu.
diff --git a/gestion/mail/template/ago/body/en.md b/gestion/mail/template/ago/body/en.md
new file mode 100644
index 00000000..fc4acf67
--- /dev/null
+++ b/gestion/mail/template/ago/body/en.md
@@ -0,0 +1,37 @@
+Dear members,
+
+The Ordinary General Meeting of the Cr@ns will take place Thursday, March 6th, 2014 at 7:15pm in Pavillon des Jardins.
+The present email serve as formal notice to attend.
+The main goal of this meeting is the election of a new Board of Directors.
+
+= Agenda =
+
+== New statutes and Internal regulation ==
+Both statutes and internal regulation have been modified. First drafts will soon be available on the wiki.
+Final versions will be available Thursday, February 27th after the last meeting of the current members from the Board of Directors. New modifications will be submitted to the vote of all members present at the General Meeting.
+
+== Activity and financial report ==
+President Ariane Soret will present the activity report.
+Treasurer Vincent Guiraud will present the financial report.
+Both reports will be submitted to the vote of all present members.
+
+== Technical report ==
+Technical Manager Valentin Samir will present the technical report.
+
+== Elections ==
+As anounced by the President, the application phase [1] lasts until Thursday, February 27th. The elections shall be held during the Ordinary General Meeting. Execution modalities will be provided later.
+
+== Counting of votes ==
+
+== Announcement of new Board of Directors ==
+
+During the Ordinary General Meeting, internet connection may be altered.
+
+After the Ordinary General Meeting, the new Board of Directors will eventually have a meeting.
+
+Good evening,
+
+--
+Raphaël-David Lasseri
+Secrétaire du Crans
+Secretary of Crans Association
diff --git a/gestion/mail/template/ago/body/fr.md b/gestion/mail/template/ago/body/fr.md
new file mode 100644
index 00000000..04932302
--- /dev/null
+++ b/gestion/mail/template/ago/body/fr.md
@@ -0,0 +1,45 @@
+Chers adhérents,
+
+Le Jeudi 6 Mars 2014, Ã partir de 19h15 au Pavillon Des Jardins aura lieu
+l'Assemblée Générale Ordinaire du Crans. Le présent mail tient lieu de
+convocation. L'objet principal de cette assemblée sera l'élection du nouveau
+Conseil d'Administration.
+
+= Ordre du jour =
+
+== Nouveaux Status et Règlement Intérieur ==
+Les Statuts et le Règlement Intérieur ont été modifiés.
+Leurs brouillons sont déja disponible sur la mailing list CA
+et seront mis en ligne très prochainement sur le wiki.
+Leurs versions finales seront disponible le jeudi 27 février à l'issue
+du dernier Conseil d'Administration du bureau actuel.
+Ces modifications seront soumises au vote des adhérents présents.
+
+== Bilans moral et financier ==
+Le président Ariane Soret présentera le bilan moral et le trésorier sortant
+Vincent Guiraud présentera le bilan financier. Ces bilans seront soumis au vote
+des adhérents présents.
+
+== Bilan technique ==
+Le responsable technique en chef Valentin Samir présentera le bilan technique.
+
+== Elections ==
+Comme précédemment annoncé par notre président. La phase de candidature [1] est
+ouverte jusqu’au jeudi 27 février. Les élections se dérouleront le jour de
+l'AGO; les modalités électorales seront communiqués ultérieurement.
+
+=== Dépouillement des votes ===
+
+=== Annonce du nouveau bureau ===
+
+Durant l'Assemblée Générale Ordinaire la connexion à Internet pourra être altérée.
+
+
+À l'issue de l'Assemblée Générale Ordinaire le nouveau Conseil d'Administration
+pourra éventuellement tenir une réunion.
+
+
+Bonne soirée à tous !
+
+ [1]: https://wiki.crans.org/CransAdministratif/R%C3%A8glementInt%C3%A9rieur
+
From 6ab35a2cfa1be40c51d8f3d564a438f344a060e9 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Fri, 21 Feb 2014 21:53:26 +0100
Subject: [PATCH 09/52] [gestion/mail] Le body de ago n'est pas en markdown
---
gestion/mail/template/ago/body/ATTENTION | 3 ---
gestion/mail/template/ago/body/{en.md => en} | 0
gestion/mail/template/ago/body/{fr.md => fr} | 0
3 files changed, 3 deletions(-)
delete mode 100644 gestion/mail/template/ago/body/ATTENTION
rename gestion/mail/template/ago/body/{en.md => en} (100%)
rename gestion/mail/template/ago/body/{fr.md => fr} (100%)
diff --git a/gestion/mail/template/ago/body/ATTENTION b/gestion/mail/template/ago/body/ATTENTION
deleted file mode 100644
index 1344cdb0..00000000
--- a/gestion/mail/template/ago/body/ATTENTION
+++ /dev/null
@@ -1,3 +0,0 @@
-Le corps des messages est rédigé en markdown
-cd http://tmpvar.com/markdown.html pour un aperçu
-du rendu.
diff --git a/gestion/mail/template/ago/body/en.md b/gestion/mail/template/ago/body/en
similarity index 100%
rename from gestion/mail/template/ago/body/en.md
rename to gestion/mail/template/ago/body/en
diff --git a/gestion/mail/template/ago/body/fr.md b/gestion/mail/template/ago/body/fr
similarity index 100%
rename from gestion/mail/template/ago/body/fr.md
rename to gestion/mail/template/ago/body/fr
From f58ef89ffcdb0ea98fac836801d66ef1f3724dae Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sat, 22 Feb 2014 18:59:53 +0100
Subject: [PATCH 10/52] [firewall4] Petit modification sur les animation de
progression
---
gestion/gen_confs/firewall4/base.py | 2 +-
gestion/gen_confs/firewall4/komaz.py | 4 ++--
gestion/gen_confs/firewall4/utils.py | 5 ++---
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/gestion/gen_confs/firewall4/base.py b/gestion/gen_confs/firewall4/base.py
index 9962ac8b..c0ca144d 100644
--- a/gestion/gen_confs/firewall4/base.py
+++ b/gestion/gen_confs/firewall4/base.py
@@ -109,9 +109,9 @@ class firewall(utils.firewall_tools) :
chain = 'BLACKLIST_HARD'
if fill_ipset:
- anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
# On récupère la liste de toutes les ips blacklistés hard
bl_hard_ips = self.blacklisted_ips(config.blacklist_sanctions, config.NETs['all'])
+ anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
print OK
diff --git a/gestion/gen_confs/firewall4/komaz.py b/gestion/gen_confs/firewall4/komaz.py
index da380759..184d6d41 100644
--- a/gestion/gen_confs/firewall4/komaz.py
+++ b/gestion/gen_confs/firewall4/komaz.py
@@ -310,9 +310,9 @@ class firewall(base.firewall_routeur):
chain = 'BLACKLIST_SOFT'
if fill_ipset:
- anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
# On récupère la liste de toutes les ips blacklistés soft
bl_soft_ips = self.blacklisted_ips(base.config.blacklist_sanctions_soft, base.config.NETs['all'])
+ anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
print OK
@@ -352,9 +352,9 @@ class firewall(base.firewall_routeur):
chain = 'BLACKLIST_UPLOAD'
if fill_ipset:
- anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['upload'])
# On récupère la liste de toutes les ips blacklistés pour upload
bl_upload_ips = self.blacklisted_ips(base.config.blacklist_bridage_upload, base.config.NETs['all'])
+ anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['upload'])
self.ipset['blacklist']['upload'].restore(bl_upload_ips)
print OK
diff --git a/gestion/gen_confs/firewall4/utils.py b/gestion/gen_confs/firewall4/utils.py
index 7e49198b..b0de0c2f 100644
--- a/gestion/gen_confs/firewall4/utils.py
+++ b/gestion/gen_confs/firewall4/utils.py
@@ -63,8 +63,10 @@ class firewall_tools(object) :
# les machine.proprio() soit déjà peuplés. En effet, on regarde
# les blacklistes d'un proprio lorsque l'on regarde les blacklistes
# d'une machine
+ anim('\tChargement des machines')
self._machines, self._adherents = self.conn.allMachinesAdherents()
self._adherents = [ adh for adh in self._adherents if adh.paiement_ok() ]
+ print OK
return self._machines
def adherents(self):
@@ -241,10 +243,7 @@ class firewall_tools(object) :
def start(self):
"""Démarre le pare-feu : génère les règles, puis les restore"""
- anim('\tChargement des machines')
self.machines()
- self.blacklisted_machines()
- print OK
if squeeze:
anim('\tVidage du pare-feu')
From 70266433532109b8d55e781e76ebde68985fe004 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sat, 22 Feb 2014 19:00:25 +0100
Subject: [PATCH 11/52] =?UTF-8?q?[gen=5Fconfs/generate]=20possibilit=C3=A9?=
=?UTF-8?q?=20de=20lancer=20trigger=20en=20arri=C3=A8re=20plan?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/generate.py | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/gestion/gen_confs/generate.py b/gestion/gen_confs/generate.py
index 5709b7e7..03f47709 100755
--- a/gestion/gen_confs/generate.py
+++ b/gestion/gen_confs/generate.py
@@ -33,7 +33,7 @@ signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
db = crans_ldap()
make_lock('auto_generate', 'Big lock', nowait=1)
-def trigger(host):
+def trigger(host, background=False):
if not 'adm.crans.org' in host:
host=host + '.adm.crans.org'
options = ['PasswordAuthentication=no', 'ConnectTimeout=1', 'VerifyHostKeyDNS=yes',
@@ -43,11 +43,14 @@ def trigger(host):
args.append('-o')
args.append(opt)
args.extend(["rpcssh@%s" % host, "generate"])
- p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- out, err = p.communicate()
- if err:
- raise Exception(err)
- return out
+ if background:
+ subprocess.Popen(args)
+ else:
+ p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ if err:
+ raise Exception(err)
+ return out
class base_reconfigure:
try:
From 17199ba9007e35882d256d97833ae243996e1ab7 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sat, 22 Feb 2014 19:01:49 +0100
Subject: [PATCH 12/52] [gen_confs/generate] --reconnect programme les
reconnexions seulement pour les prochaines 24h
---
gestion/gen_confs/generate.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/gestion/gen_confs/generate.py b/gestion/gen_confs/generate.py
index 03f47709..c2fb4f69 100755
--- a/gestion/gen_confs/generate.py
+++ b/gestion/gen_confs/generate.py
@@ -381,15 +381,17 @@ if __name__ == '__main__':
print 'Recherche des personnes en fin de sanction...'
c = db.search('blacklist=*')
services = []
+ nom = time()
hier = time() - 24*3600
+ demain = time() + 24*3600
for a_reco in c['adherent'] + c['machine'] + c['club']:
for bl in a_reco.blacklist():
fin, sanction = bl.split('$')[1:3]
- if fin > hier and sanction not in services:
- services.append(sanction)
- for s in services:
+ if fin != '-' and fin <= demain and fin >= now and (sanction, fin) not in services:
+ services.append((sanction, fin))
+ for s,f in services:
print "Ajout de blacklist_%s pour reconfiguration" % s
- db.services_to_restart('blacklist_%s' % s)
+ db.services_to_restart('blacklist_%s' % s, start=f)
sys.exit(0)
elif opt == '--add':
From 47ee3eed1cc3cd7a4760eccd0e83953b9970e08d Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sun, 23 Feb 2014 00:22:38 +0100
Subject: [PATCH 13/52] [bind] Ajout d'enregistrement tls depuis la base ldap
---
gestion/gen_confs/bind.py | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/gestion/gen_confs/bind.py b/gestion/gen_confs/bind.py
index 1508e05d..7d20d025 100755
--- a/gestion/gen_confs/bind.py
+++ b/gestion/gen_confs/bind.py
@@ -51,17 +51,18 @@ class ResourceRecord(object):
return str(self)
class TLSA(ResourceRecord):
- def __init__(self, name, port, proto, cert, certtype, reftype, compat=True, ttl=None):
+ def __init__(self, name, port, proto, cert, certtype, reftype, selector=0, compat=True, format='pem', ttl=None):
"""
name: nom du domaine du certificat
port: port où écoute le service utilisant le certificat
proto: udp ou tcp
- cert: le certificat au format pem (selector est donc toujours à 0)
+ cert: le certificat au format ``format`` (pem ou der) (selector est donc toujours à 0)
certtype: type d'enregistrement 0 = CA pinning, 1 = cert pinning, 2 = self trusted CA, 3 = self trusted cert
reftype: 0 = plain cert, 1 = sha256, 2 = sha512
compat: on génère un enregistement compris même par les serveurs dns n'implémentant pas TLSA
"""
- selector = 0
+ if not format in ['pem', 'der']:
+ raise ValueError("format should be pem or der")
if cert is None and proto == 'tcp' and name[-1] == '.':
try:
cert = ssl.get_server_certificate((name[:-1], port), ca_certs='/etc/ssl/certs/ca-certificates.crt')
@@ -69,10 +70,13 @@ class TLSA(ResourceRecord):
raise ValueError("Unable de retrieve cert dynamically: %s" % e)
elif cert is None:
raise ValueError("cert can only be retrive if proto is tcp and name fqdn")
- dercert = ssl.PEM_cert_to_DER_cert(cert)
+ if format is not 'der':
+ dercert = ssl.PEM_cert_to_DER_cert(cert)
+ else:
+ dercert = cert
if not dercert:
raise ValueError("Impossible de convertir le certificat au format DER %s %s %s\n%s" % (name, port, proto, cert))
- certhex = TLSA.hashCert(reftype, dercert)
+ certhex = TLSA.hashCert(reftype, str(dercert))
if compat:
super(TLSA, self).__init__(
'TYPE52',
@@ -271,6 +275,16 @@ class Zone(ZoneBase):
except (KeyError, TypeError):
pass
+ def add_tlsa_record(self, cert):
+ if 'TLSACert' in cert['objectClass']:
+ for host in cert['hostCert']:
+ nom=self.get_name(host)
+ if nom is None: continue
+ for port in cert['portTCPin']:
+ self.add(TLSA(nom, port, 'tcp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], format='der'))
+ for port in cert['portUDPin']:
+ self.add(TLSA(nom, port, 'udp', cert['certificat'][0], cert['certificatUsage'][0], cert['matchingType'][0], cert['selector'][0], format='der'))
+
def add_machine(self, machine):
for host in machine['host']:
nom=self.get_name(host)
@@ -279,6 +293,8 @@ class Zone(ZoneBase):
self.add_a_record(nom, machine)
self.add_aaaa_record(nom, machine)
self.add_sshfp_record(nom, machine)
+ for cert in machine.certificats():
+ self.add_tlsa_record(cert)
if machine['host']:
From 4ce302b69991caf84a4e1dacdaed011e52104f90 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sun, 23 Feb 2014 02:13:08 +0100
Subject: [PATCH 14/52] dhcpd: drope les macs ""
---
gestion/gen_confs/dhcpd_new.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gestion/gen_confs/dhcpd_new.py b/gestion/gen_confs/dhcpd_new.py
index 9c24f367..b86b1479 100644
--- a/gestion/gen_confs/dhcpd_new.py
+++ b/gestion/gen_confs/dhcpd_new.py
@@ -36,6 +36,8 @@ class dydhcp:
@raises OmapiError:
@raises socket.error:
"""
+ if '' in [ip, mac]:
+ return
msg = OmapiMessage.open(b"host")
msg.message.append((b"create", struct.pack("!I", 1)))
msg.message.append((b"exclusive", struct.pack("!I", 1)))
@@ -56,6 +58,8 @@ class dydhcp:
@raises OmapiError:
@raises socket.error:
"""
+ if '' in [ip, mac]:
+ return
msg = OmapiMessage.open(b"host")
msg.obj.append((b"hardware-address", pack_mac(mac)))
msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
@@ -147,7 +151,8 @@ class dhcp(gen_config) :
for machine in self.machines :
self.anim.cycle()
for net in self.reseaux.keys() :
- if machine.ip() != '' and AddrInNet(machine.ip(), net) :
+ if '' not in [machine.ip(), machine.mac()] and \
+ AddrInNet(machine.ip(), net):
host_template = self.host_template
# variable pour remplir le template
#d = { 'nom' : machine.nom().split('.')[0] , 'mac' : machine.mac() , 'ip' : machine.ip() }
From bbb12b733f5f137d7c134f5ad39d1d96040ca61c Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sun, 23 Feb 2014 02:28:29 +0100
Subject: [PATCH 15/52] radius: fonction get_prise
---
freeradius/auth.py | 37 ++++++++++++++++++++++++++-------
freeradius/rlm_python_wifi.conf | 34 ++++++++++++++++--------------
2 files changed, 47 insertions(+), 24 deletions(-)
diff --git a/freeradius/auth.py b/freeradius/auth.py
index 9a9b2d2d..f45aa9af 100644
--- a/freeradius/auth.py
+++ b/freeradius/auth.py
@@ -62,6 +62,35 @@ def get_machines(auth_data, conn):
conn.search(u'(&%s(|(macAddress=%s)(host=%s.wifi.crans.org)))' %
(base, username, username))
+def get_prise(auth_data):
+ """Extrait la prise"""
+ ## Regarder dans
+ ## Filaire: NAS-Identifier => contient le nom du switch (batm-3.adm.crans.org)
+ ## Nas-Port => port du switch (ex 42)
+ ## WiFi: NAS-Identifier => vide
+ ## Nas-Port => numéro sur l'interface
+ ## Nas-IP-Address => adresse IP de la borne
+ is_wifi = True
+ bat_name = None
+ bat_num = None
+ port = None
+
+ for (key, value) in auth_data:
+ if key == 'NAS-Identifier':
+ if value.startswith('bat'):
+ nas = value.split('.', 1)[0]
+ try:
+ bat_name = nas[3]
+ bat_num = nas.split('-', 1)[1]
+ except IndexError:
+ pass
+
+ if key == 'Nas-Port':
+ port = int(value)
+
+ if bat_num and bat_name and port:
+ return bat_name + "%01d%02d" % (bat_num, port)
+
# Decorateur utilisé plus tard (same connection)
use_ldap = with_ldap_conn(retries=2, delay=5, constructor=lc_ldap_anonymous)
@@ -182,14 +211,6 @@ def post_auth(auth_data, conn):
def dummy_fun(p):
return radiusd.RLM_MODULE_OK
-recv_coa = dummy_fun
-send_coa = dummy_fun
-preacct = dummy_fun
-accounting = dummy_fun
-pre_proxy = dummy_fun
-post_proxy = dummy_fun
-
-
def detach(p=None):
"""Appelé lors du déchargement du module (enfin, normalement)"""
print "*** goodbye from example.py ***"
diff --git a/freeradius/rlm_python_wifi.conf b/freeradius/rlm_python_wifi.conf
index 297cf776..a8b73e2b 100644
--- a/freeradius/rlm_python_wifi.conf
+++ b/freeradius/rlm_python_wifi.conf
@@ -11,25 +11,27 @@ python crans_wifi {
func_authorize = wifi_authorize
# Renseigne le vlan
+ # remplacer par dummy_fun pour ignorer le tagging de vlan
mod_post_auth = freeradius.auth
func_post_auth = post_auth
- # Le reste est dumb et inutile
- mod_accounting = freeradius.auth
- func_accounting = accounting
-
- mod_pre_proxy = freeradius.auth
- func_pre_proxy = pre_proxy
-
- mod_post_proxy = freeradius.auth
- func_post_proxy = post_proxy
-
- mod_recv_coa = freeradius.auth
- func_recv_coa = recv_coa
-
- mod_send_coa = freeradius.auth
- func_send_coa = send_coa
-
+ # Que faire avant de quitter
mod_detach = freeradius.auth
func_detach = detach
+
+ # Le reste est dumb et inutile
+ mod_accounting = freeradius.auth
+ func_accounting = dummy_fun
+
+ mod_pre_proxy = freeradius.auth
+ func_pre_proxy = dummy_fun
+
+ mod_post_proxy = freeradius.auth
+ func_post_proxy = dummy_fun
+
+ mod_recv_coa = freeradius.auth
+ func_recv_coa = dummy_fun
+
+ mod_send_coa = freeradius.auth
+ func_send_coa = dummy_fun
}
From e14bb4ac909703d13cbaa5d1c9f261c3a43b0f8e Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sun, 23 Feb 2014 02:32:11 +0100
Subject: [PATCH 16/52] =?UTF-8?q?trucs=20d=C3=A9pr=C3=A9ci=C3=A9s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/ipset.py | 3 ---
gestion/restore.py | 4 ++++
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/gestion/gen_confs/ipset.py b/gestion/gen_confs/ipset.py
index 128db479..5a27b0cc 100644
--- a/gestion/gen_confs/ipset.py
+++ b/gestion/gen_confs/ipset.py
@@ -19,11 +19,8 @@ import sys
sys.path.append('/usr/scripts/gestion')
import commands
-import lock
import os
-
-
class IpsetError(Exception):
# Gestion des erreurs d'ipset
def __init__(self,cmd,err_code,output):
diff --git a/gestion/restore.py b/gestion/restore.py
index 39205926..7c701933 100755
--- a/gestion/restore.py
+++ b/gestion/restore.py
@@ -11,6 +11,10 @@ Attention, ce fichier est osbolète
"""
import cPickle, sys
+if '/usr/scripts' not in sys.path:
+ sys.path.append('/usr/scripts')
+from cranslib.deprecated import module as dep_module
+dep_module('ressucite or ressucite_lc')
import config
from whos import aff
From eb6116026f3aaad8f7938c135bfce66aa37c9235 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sun, 23 Feb 2014 16:31:42 +0100
Subject: [PATCH 17/52] [chambres_vides] lc_ldapisation et gestion des erreurs
lors de la suppression d'une machine
---
gestion/chambres_vides.py | 46 ++++++++++++++++++++++++++++-----------
1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/gestion/chambres_vides.py b/gestion/chambres_vides.py
index 3b49dd57..fdb74c46 100755
--- a/gestion/chambres_vides.py
+++ b/gestion/chambres_vides.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/bin/bash /usr/scripts/python.sh
# -*- encoding: utf-8 -*-
""" Pour détecter les gens en chambre invalide, les prévenir, et supprimer leurs machines
@@ -12,8 +12,8 @@
import datetime
import time
import re
-import ldap_crans
-conn = ldap_crans.CransLdap()
+import lc_ldap.shortcuts
+conn = lc_ldap.shortcuts.lc_ldap_admin()
import mail as mail_module
import sys
@@ -39,19 +39,20 @@ delai = config.demenagement_delai
# On récupère ceux qui n'ont pas payé cette année
if config.periode_transitoire:
- bad_boys_e_s = conn.search('chbre=????&paiement=%d&paiement!=%d' % (year-1,year))['adherent']
+ bad_boys_e_s = conn.search(u'(&(aid)*)(chbre=????)(paiement=%d)(!(paiement=%d)))' % (year-1,year))
else:
- bad_boys_e_s = conn.search('chbre=????&paiement=%d' % year)['adherent']
+ bad_boys_e_s = conn.search(u'(&(aid=*)(chbre=????)(paiement=%d))' % year)
now = time.time()
to_print = []
+to_error = []
for clandestin in bad_boys_e_s:
# On cherche la dernière fois qu'il s'est retrouvé en chambre ????
- for l in clandestin.historique():
+ for l in clandestin['historique'][::-1]:
# On récupère la date du dernier changement de chambre
# (l'historique est enregistré par ordre chronologique)
- x = re.match("(.*),.* : chbre \((.*) -> \?\?\?\?\)",l)
+ x = re.match("(.*),.* : chbre \((.*) -> \?\?\?\?\)", str(l))
if x <> None:
kickout_date = x.group(1)
exchambre = x.group(2)
@@ -64,7 +65,7 @@ for clandestin in bad_boys_e_s:
if ttl > 0:
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
- to = clandestin.mail()
+ to = clandestin['mail'][0]
if not "@" in to:
to += "@crans.org"
mail = mail_module.generate('demenagement', {"from" : "respbats@crans.org",
@@ -81,16 +82,19 @@ for clandestin in bad_boys_e_s:
else:
for m in machine_liste:
- to_print.append( (clandestin.id(), m.ip(), m.id(), m.nom()) )
- m2 = conn.search('mid=%s' % m.id(),mode='w')['machine'][0]
- m2.delete('Adherent sans chambre valide depuis %d jours' % delai)
+ try:
+ m2 = conn.search(u'mid=%s' % m['mid'][0],mode='w')[0]
+ m2.delete('Adherent sans chambre valide depuis %d jours' % delai)
+ to_print.append( (clandestin['aid'][0], m['ipHostNumber'][0], m['mid'][0], m['host'][0]) )
+ except Exception as e:
+ to_error.append((clandestin['aid'][0], m['ipHostNumber'][0], m['mid'][0], m['host'][0], e))
+message = u""
if to_print != []:
# Il s'est passé quelque chose, donc on envoie un mail
# On regarde le plus grand hostname
- hostnamemaxsize = max([len(i[3]) for i in to_print])
+ hostnamemaxsize = max([len(str(i[3])) for i in to_print])
template = u"| %%4s | %%-15s | %%4s | %%-%ss |\n" % (hostnamemaxsize)
- message = u""
message += u"\nListe des machines supprimées pour chambre invalide depuis plus de %s jours :\n" % delai
tiret_line = u"+------+-----------------+------+-%s-+\n" % ("-" * hostnamemaxsize)
message += tiret_line
@@ -98,8 +102,24 @@ if to_print != []:
message += tiret_line
for aid, ip, mid, hostname in to_print:
message += template % (aid, ip, mid, hostname)
+
message += tiret_line
message += u"\nScore de cette nuit : %s" % (len(to_print))
+
+if to_error != []:
+ hostnamemaxsize = max([len(str(i[3])) for i in to_error])
+ errormaxsize = max([len(str(i[4])) for i in to_error])
+ template = u"| %%4s | %%-15s | %%4s | %%-%ss | %%-%ss |\n" % (hostnamemaxsize, errormaxsize)
+ message += u"\n"
+ tiret_line = u"+------+-----------------+------+-%s-+-%s-+\n" % ("-" * hostnamemaxsize, "-" * errormaxsize)
+ message += u"\nListe des machines dont la supression à échoué :\n"
+ message += tiret_line
+ message += template % ("aid", " ip", "mid", (" " * (max((hostnamemaxsize-8)/2,0)) + "hostname"), (" " * (max((errormaxsize-6)/2,0)) + "erreur"))
+ for aid, ip, mid, hostname, error in to_error:
+ message += template % (aid, ip, mid, hostname, error)
+ message += tiret_line
+
+if to_print != [] or to_error != []:
headers = u"From: respbats@crans.org\nSubject: %s\n" % Header("Machines supprimées pour chambre invalide", "utf8").encode()
headers += u"Content-Type: text/plain; charset=UTF-8\n"
headers += u"X-Mailer: /usr/scripts/gestion/chambres_vides.py\n"
From 5c9e740f7391f9540bebf8bf3468489a2ece7283 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sun, 23 Feb 2014 16:32:29 +0100
Subject: [PATCH 18/52] [gestion/mail] Exemple plus complet en commentaire
---
gestion/mail/mail.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gestion/mail/mail.py b/gestion/mail/mail.py
index 14676626..be8da1da 100644
--- a/gestion/mail/mail.py
+++ b/gestion/mail/mail.py
@@ -32,7 +32,7 @@ markup = {
### For an example:
### print generate('bienvenue', {'From':'respbats@crans.org', 'To':'admin@genua.fr', 'lang_info':'English version below'}).as_string()
-
+### or from a shell : python -c "import mail; print mail.generate('bienvenue', {'From':'respbats@crans.org', 'To':'admin@genua.fr', 'lang_info':'English version below'})"
def submessage(playload, type, charset='utf-8'):
"""Renvois un sous message à mettre dans un message multipart"""
From ff88440f2e79bb58f0ea373d9565aa7df924cef4 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sun, 23 Feb 2014 16:58:59 +0100
Subject: [PATCH 19/52] ldap_crans: valeur "" pour champ mac
Et on vire l'ipv6 dans ce cas.
---
gestion/ip6tools.py | 4 ++++
gestion/ldap_crans.py | 18 ++++++++++++++++--
gestion/whos.py | 3 ++-
3 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/gestion/ip6tools.py b/gestion/ip6tools.py
index 58575b9d..01c2db61 100644
--- a/gestion/ip6tools.py
+++ b/gestion/ip6tools.py
@@ -24,7 +24,11 @@ import netaddr
def mac_to_ipv6(ipv6_prefix, mac_address):
"""Convert a MAC address (EUI48) to an IPv6 (prefix::EUI64)."""
+ if mac_address == '':
+ return ''
+ if type(mac_address) in [str, unicode]:
+ mac_address = netaddr.EUI(mac_address)
addr = int(mac_address.bits(netaddr.mac_bare), 2)
ip6addr = (((addr >> 24) ^ (1 << 17)) << 40) | (0xFFFE << 24) | (addr & 0xFFFFFF)
n = netaddr.IPNetwork(ipv6_prefix)
diff --git a/gestion/ldap_crans.py b/gestion/ldap_crans.py
index 236a2fe7..c1d9a768 100755
--- a/gestion/ldap_crans.py
+++ b/gestion/ldap_crans.py
@@ -223,6 +223,9 @@ def format_mac(mac):
Le séparateur original peut être :, - ou rien
Retourne la mac formatée.
"""
+ mac = mac.strip()
+ if mac == '':
+ return mac
l, mac = preattr(mac)
mac = mac.strip().replace(' ','').replace("-", ":")
if mac.count(":") == 5:
@@ -2863,6 +2866,10 @@ class Machine(BaseClasseCrans):
mac = format_mac(mac)
+ if mac == '':
+ multi_ok = True
+ lock = False
+
# La MAC serait-elle une MAC Ã la con ?
if mac == "00:04:4b:80:80:03":
raise ValueError(u"Il s'agit de l'unique adresse MAC achetée par nVidia pour ses cartes réseau. Il faut changer cette adresse.", 2)
@@ -2898,7 +2905,7 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
try:
self._set('macAddress', [mac])
if net.size > 1:
- self.ipv6(ip6tools.mac_to_ipv6(net, netaddr.EUI(mac)), lock)
+ self.ipv6(ip6tools.mac_to_ipv6(net, mac), lock)
else:
self.ipv6(config.ipv6_machines_speciales[int(self.rid())], lock)
except Exception as e:
@@ -3390,7 +3397,14 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
"""Retourne l'adresse IPv6 correspondant à la machine"""
if ipv6 == None:
- return netaddr.IPAddress(self._data.get('ip6HostNumber', [''])[0])
+ if self._data.get('ip6HostNumber', []) == []:
+ return None
+ else:
+ return netaddr.IPAddress(self._data.get('ip6HostNumber')[0])
+
+ if ipv6 == '':
+ self._set('ip6HostNumber', [])
+ return
ipv6 = str(ipv6)
net = self.netv6()
diff --git a/gestion/whos.py b/gestion/whos.py
index a03d141e..f6a6f5ec 100755
--- a/gestion/whos.py
+++ b/gestion/whos.py
@@ -670,7 +670,8 @@ def machine_details(machine) :
f+= coul(u'IP : ','gras') + "%s\t\t" %machine.ip()
f+= coul(u'MAC : ','gras') + "%s\n" %machine.mac()
- f+= coul(u'IPv6 : ','gras') + "%s\n" %machine.ipv6()
+ if machine.ipv6() != None:
+ f+= coul(u'IPv6 : ','gras') + "%s\n" %machine.ipv6()
if len(machine.sshFingerprint()) > 0 and aff_ssh:
f += u"\n".join([coul(u'Fingerprint SSH : ', 'gras') + u"%s" % (i) for i in machine.sshFingerprint()])+"\n"
From 328904ae19ce4a75ae2868c8d0daa8346e2def09 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sun, 23 Feb 2014 17:22:39 +0100
Subject: [PATCH 20/52] [ldap_crans] ldap_crans ne modifie pas les host,
hostAlias d'une machine ayant des certificats
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
C'est brûtal, mais je n'ai pas tu tout envie d'implémenter les certificat dans ldap_crans.
On moins on peut toujours ajouter de nouveaux alias.
De plus on interdit aussi la suppression d'une telle machine.
---
gestion/gest_crans.py | 4 ++--
gestion/ldap_crans.py | 12 ++++++++++++
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/gestion/gest_crans.py b/gestion/gest_crans.py
index 1427fa02..5883b98a 100755
--- a/gestion/gest_crans.py
+++ b/gestion/gest_crans.py
@@ -933,7 +933,7 @@ def __prompt_input_menu(method, titre, prompt):
else:
method([num-1, val])
- except ValueError, c:
+ except (EnvironmentError, ValueError) as c:
arg = u'--title "%s" ' % titre
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(c.args[0])
dialog(arg)
@@ -1135,7 +1135,7 @@ def confirm(clas):
return 1
try:
res = clas.save()
- except RuntimeError, c:
+ except (EnvironmentError, RuntimeError) as c:
arg = u'--title "Enregistrement" '
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(c.args[0])
dialog(arg)
diff --git a/gestion/ldap_crans.py b/gestion/ldap_crans.py
index c1d9a768..3d521fc5 100755
--- a/gestion/ldap_crans.py
+++ b/gestion/ldap_crans.py
@@ -3008,6 +3008,9 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
if type(new) == list:
# Modif
+ res = self.conn.search_s(self.dn, 1, "xid=*")
+ if res:
+ raise EnvironmentError("La machine possède des certificats, utilisez lc_ldap ou l'intranet2")
index = new[0]
new = new[1]
if new == '':
@@ -3221,6 +3224,12 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
ret = ''
+ # test si la machine a des certificats
+ if 'host' in self.modifs:
+ res = self.conn.search_s(self.dn, 1, "xid=*")
+ if res:
+ raise EnvironmentError("La machine possède des certificats, utilisez lc_ldap ou l'intranet2")
+
# Besoin de redémarrer les firewalls ?
if 'ipHostNumber' in self.modifs or 'macAddress' in self.modifs:
reconf_ip = self._init_data.get('ipHostNumber', [])
@@ -3301,6 +3310,9 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
if self.proprietaire().__class__ == AssociationCrans and not isadm():
raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.')
+ res = self.conn.search_s(self.dn, 1, "xid=*")
+ if res:
+ raise EnvironmentError("La machine possède des certificats, utilisez lc_ldap ou l'intranet2")
self.proprio = self.__proprietaire.Nom() # On met dans un coin le nom du proprio
self.__proprietaire = None # On oublie le propriétaire
From ce214d8bd8401404f2d0e851581cf0e3fc087397 Mon Sep 17 00:00:00 2001
From: Aymeric LABATUT
Date: Sun, 23 Feb 2014 19:07:09 +0100
Subject: [PATCH 21/52] [firewall4]drope les mac
---
gestion/gen_confs/firewall4/base.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/gestion/gen_confs/firewall4/base.py b/gestion/gen_confs/firewall4/base.py
index c0ca144d..e36ecf81 100644
--- a/gestion/gen_confs/firewall4/base.py
+++ b/gestion/gen_confs/firewall4/base.py
@@ -128,6 +128,8 @@ class firewall(utils.firewall_tools) :
def test_mac_ip_dispatch(self, func, machine):
"""Détermine à quel set de mac-ip appliquer la fonction ``func`` (add, delete, append, ...)"""
ips = machine['ipHostNumber']
+ if '' in machine['macAddress'] :
+ return
for ip in ips:
# Si la machines est sur le réseau des adhérents
if utils.AddrInNet(str(ip), config.NETs['wifi']):
@@ -201,6 +203,8 @@ class firewall_routeur(firewall):
def test_mac_ip_dispatch(self, func, machine):
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
ips = machine['ipHostNumber']
+ if '' in machine['macAddress'] :
+ return
for ip in ips:
# Si la machines est sur le réseau des adhérents
if utils.AddrInNet(str(ip), config.NETs['wifi']):
@@ -219,6 +223,8 @@ class firewall_wifionly(firewall):
def test_mac_ip_dispatch(self, func, machine):
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
ips = machine['ipHostNumber']
+ if '' in machine['macAddress'] :
+ return
for ip in ips:
# Si la machines est sur le réseau des adhérents
if utils.AddrInNet(str(ip), config.NETs['wifi']):
From 9d7d80d8d1f52990e02152218144b86661f6a94a Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sun, 23 Feb 2014 19:30:38 +0100
Subject: [PATCH 22/52] [firewall6] drop macAddress ""
---
gestion/ipt.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/gestion/ipt.py b/gestion/ipt.py
index 70ca4d7c..37c0a1c9 100644
--- a/gestion/ipt.py
+++ b/gestion/ipt.py
@@ -30,6 +30,7 @@ from iptools import AddrInNet
from ridtools import Rid, find_rid_plage
import subprocess
import netaddr
+import ip6tools
blacklist_sanctions_ipv6 = list(blacklist_sanctions)
blacklist_sanctions_ipv6.extend(blacklist_sanctions_soft)
@@ -126,6 +127,8 @@ class Ip6tables(object):
def macip(self, mac, type_m):
'''Fait la correspondance MAC-IP'''
+ if '' == mac:
+ return
tab = {'serveurs' : 'fil' }
if type_m in tab.keys(): type_m = tab[type_m]
type_mm = re.sub('-', '', type_m)
@@ -141,6 +144,8 @@ class Ip6tables(object):
'wifi-adh-v6' : 'extwifiv6',
'serveurs':'extfil' }
ip = ipv6_addr(mac, type_machine)
+ if not ip:
+ return
for proto in ['tcp', 'udp']:
for port in ports[proto]:
if port != ':':
@@ -157,6 +162,8 @@ ACCEPT' % (dev, proto, ip, port))
'wifi-adh-v6' : 'cranswifiv6',
'serveurs':'cransfil' }
ip = ipv6_addr(mac, type_machine)
+ if not ip:
+ return
for proto in ['tcp', 'udp']:
for port in ports[proto]:
if port != ':':
@@ -470,9 +477,7 @@ def check_ip_proto(ip_proto):
def ipv6_addr(mac, net):
''' Renvoie l'adresse ipv6 d'auto-configuration de la mac sur le réseau '''
- mac_s = mac.split(':')
- eui = hex(int(mac_s[0],16) ^ 0x02)[2:] + ':'.join(mac_s[1:3]) + 'ff:fe' + ':'.join(mac_s[3:5]) + mac_s[5]
- return re.sub(':/64', eui , prefix[dprefix[net]][0])
+ return ip6tools.mac_to_ipv6(prefix[dprefix[net]][0], mac)
def mac_addr(ipv6):
''' Renvoie l'adresse mac de l'ipv6 d'auto-configuration '''
From ab6eb330720075a8cbc0d58155fd1442b707e7e3 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sun, 23 Feb 2014 19:48:07 +0100
Subject: [PATCH 23/52] virtualisation/vmid: vm id of qm name
---
gestion/virtualisation/vmid | 46 +++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100755 gestion/virtualisation/vmid
diff --git a/gestion/virtualisation/vmid b/gestion/virtualisation/vmid
new file mode 100755
index 00000000..863f0e2f
--- /dev/null
+++ b/gestion/virtualisation/vmid
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+VM_PATH=/etc/pve/qemu-server
+PVE_PATH=/etc/pve
+LOCAL_VM_PATH=/etc/pve/local/qemu-server
+SERIAL_PATH=/var/run/qemu-server
+
+if [[ ! -d /etc/pve ]]; then
+ echo "Not a proxmox server !"
+ exit 1
+fi
+
+if [[ -z "$1" ]]; then
+ echo "Please give vmid or pve name"
+ exit 5
+fi
+
+if [[ "`whoami`" != "root" ]]; then
+ echo "You must probably be root"
+ exit 42
+fi
+
+if [[ $1 != *[!0-9]* ]]; then
+ vmid=$1
+else
+ echo "Looking for vmid of $1 ..."
+ for host in `ls $PVE_PATH/nodes`; do
+ p=$PVE_PATH/nodes/$host/qemu-server
+ for f in `ls $p`; do
+ grep "name: *$1" $p/$f -q && {
+ vmid=`echo $f | grep -o "[0-9]*"`
+ node=$host
+ echo "Found vmid $vmid"
+ break
+ }
+ done
+ done
+ if [[ -z "$node" ]]; then
+ echo "vmid not found"
+ exit 2
+ fi
+ if [[ "$node" != "`hostname`" ]]; then
+ echo "Wrong node (go to $node)"
+ exit 3
+ fi
+fi
From 5ff805835076c1c3c888754b66fc4bc8b50c94dc Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Mon, 24 Feb 2014 00:31:47 +0100
Subject: [PATCH 24/52] =?UTF-8?q?virtualisation:=20script=20pour=20g=C3=A9?=
=?UTF-8?q?n=C3=A9rer=20le=20net=20udev?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Le static-rules ne semble pas contenir grand chose, voire des trucs faux
(des infos sur les macs du virtualiseur xen, sic). J'ai donc fait
un mini script pour printer ce qu'on voudrait avoir dans le udev. À éxécuter
sur la vm avant de l'éteindre.
---
gestion/virtualisation/gen_net_udev.sh | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100755 gestion/virtualisation/gen_net_udev.sh
diff --git a/gestion/virtualisation/gen_net_udev.sh b/gestion/virtualisation/gen_net_udev.sh
new file mode 100755
index 00000000..fd13679a
--- /dev/null
+++ b/gestion/virtualisation/gen_net_udev.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+
+# Sur certains virtualiseurs xen, les interfaces xen n'étaient pas dans udev.
+# Voici un petit script qui écrit les règles correspondantes
+
+ip -o l show | sed 's/^[0-9]*: \(eth[^:]*\).*ether \([^ ]*\) .*$/SUBSYSTEM=="net", DRIVERS=="?*", ATTR{address}=="\2", NAME="\1"/; t; d'
+
From 2c6cdb7201ef0d8f8347cbe3b93a927442e64158 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 24 Feb 2014 17:18:40 +0100
Subject: [PATCH 25/52] [wiki/theme/crans] On retire la liste des "sister
pages" du panel de droite
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
sinon, le champs recherche vas se cacher hors écrans pour les gens qui n'ont pas de 1080p
---
wiki/theme/crans.py | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/wiki/theme/crans.py b/wiki/theme/crans.py
index 31a6b0cd..6bd3e02c 100644
--- a/wiki/theme/crans.py
+++ b/wiki/theme/crans.py
@@ -101,6 +101,49 @@ class Theme(ThemeBase):
'{o}': ("{o}", "star_off.png", 16, 16),
}
+ def navibar(self, d):
+ """ Assemble the navibar
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: navibar html
+ """
+ request = self.request
+ found = {} # pages we found. prevent duplicates
+ items = [] # navibar items
+ item = u'%s'
+ current = d['page_name']
+
+ # Process config navi_bar
+ if request.cfg.navi_bar:
+ for text in request.cfg.navi_bar:
+ pagename, link = self.splitNavilink(text)
+ if pagename == current:
+ cls = 'wikilink current'
+ else:
+ cls = 'wikilink'
+ items.append(item % (cls, link))
+ found[pagename] = 1
+
+ # Add current page at end of local pages
+ if not current in found:
+ title = d['page'].split_title()
+ title = self.shortenPagename(title)
+ link = d['page'].link_to(request, title)
+ cls = 'current'
+ items.append(item % (cls, link))
+
+ # Assemble html
+ items = u''.join(items)
+ html = u'''
+
+''' % items
+ return html
+
+
+
def wikipanel(self, d):
""" Create wiki panel """
_ = self.request.getText
From 9a93373ab89af46080d6173da7662859110c87f6 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 24 Feb 2014 17:20:10 +0100
Subject: [PATCH 26/52] [gen_confs/generate] Modification du handling des
signaux seulement dans le __main__
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
sinon, ça fait du caca quand on veux l'importer
---
gestion/gen_confs/generate.py | 5 ++--
wiki/theme/crans.py | 43 -----------------------------------
2 files changed, 2 insertions(+), 46 deletions(-)
diff --git a/gestion/gen_confs/generate.py b/gestion/gen_confs/generate.py
index c2fb4f69..c6c7eed3 100755
--- a/gestion/gen_confs/generate.py
+++ b/gestion/gen_confs/generate.py
@@ -28,8 +28,6 @@ from syslog import *
import platform
openlog("generate")
-signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
-
db = crans_ldap()
make_lock('auto_generate', 'Big lock', nowait=1)
@@ -323,10 +321,10 @@ class gordon(base_reconfigure) :
class titanic(base_reconfigure):
pass
-signal.signal(signal.SIGINT, signal.SIG_DFL) # Comportement normal de Ctrl-C
remove_lock('auto_generate')
if __name__ == '__main__':
+ signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
openlog('generate', LOG_PID)
for x in db.services_to_restart():
try:
@@ -418,3 +416,4 @@ if __name__ == '__main__':
# On fait ce qu'il y a à faire
classe(to_do)
+ signal.signal(signal.SIGINT, signal.SIG_DFL) # Comportement normal de Ctrl-C
diff --git a/wiki/theme/crans.py b/wiki/theme/crans.py
index 6bd3e02c..31a6b0cd 100644
--- a/wiki/theme/crans.py
+++ b/wiki/theme/crans.py
@@ -101,49 +101,6 @@ class Theme(ThemeBase):
'{o}': ("{o}", "star_off.png", 16, 16),
}
- def navibar(self, d):
- """ Assemble the navibar
-
- @param d: parameter dictionary
- @rtype: unicode
- @return: navibar html
- """
- request = self.request
- found = {} # pages we found. prevent duplicates
- items = [] # navibar items
- item = u'%s'
- current = d['page_name']
-
- # Process config navi_bar
- if request.cfg.navi_bar:
- for text in request.cfg.navi_bar:
- pagename, link = self.splitNavilink(text)
- if pagename == current:
- cls = 'wikilink current'
- else:
- cls = 'wikilink'
- items.append(item % (cls, link))
- found[pagename] = 1
-
- # Add current page at end of local pages
- if not current in found:
- title = d['page'].split_title()
- title = self.shortenPagename(title)
- link = d['page'].link_to(request, title)
- cls = 'current'
- items.append(item % (cls, link))
-
- # Assemble html
- items = u''.join(items)
- html = u'''
-
-''' % items
- return html
-
-
-
def wikipanel(self, d):
""" Create wiki panel """
_ = self.request.getText
From e7563a2d15d1f83d04a35c92716636b881c7101e Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Mon, 24 Feb 2014 17:38:46 +0100
Subject: [PATCH 27/52] gen_conf/surveillance: droppe ipv6 vide
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Il se peut qu'une machine n'ait pas d'ipv6, on évite de remplir la base pg
avec un "None" (qui va échouer). Remarque qu'on pourrait peut-être mettre la
valeur Null, mais bon…
---
gestion/gen_confs/surveillance.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/gestion/gen_confs/surveillance.py b/gestion/gen_confs/surveillance.py
index 8f20498a..74ca7877 100644
--- a/gestion/gen_confs/surveillance.py
+++ b/gestion/gen_confs/surveillance.py
@@ -49,6 +49,9 @@ class exemptions(gen_config) :
source = machine.ip()
else:
source = machine.ipv6()
+ # Si ip vide, passons au suivant
+ if not source:
+ continue
requete="INSERT INTO exemptes (ip_crans,ip_dest) VALUES ('%s','%s')" % (source, destination)
curseur.execute(requete)
@@ -83,6 +86,10 @@ class machines(gen_config) :
ipv6_vu={}
def ipv6_already_set(ipv6):
+ # S'il ne s'agit pas d'une IP valide (vide ?) faisons comme si
+ # on l'avait déjà vue :p
+ if not ipv6:
+ return True
ret = ipv6_vu.get(ipv6, False)
ipv6_vu[ipv6] = True
return ret
From 2acb941864c77ca62b9ce9f5e0b392c3cf92de48 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 24 Feb 2014 18:53:36 +0100
Subject: [PATCH 28/52] [wiki/theme/crans] On retire la liste des "sister
pages" du panel de droite
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
sinon, le champs recherche vas se cacher hors écrans pour les gens qui n'ont pas de 1080p
truc étrange au commit précédent précédent
---
wiki/theme/crans.py | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/wiki/theme/crans.py b/wiki/theme/crans.py
index 31a6b0cd..6bd3e02c 100644
--- a/wiki/theme/crans.py
+++ b/wiki/theme/crans.py
@@ -101,6 +101,49 @@ class Theme(ThemeBase):
'{o}': ("{o}", "star_off.png", 16, 16),
}
+ def navibar(self, d):
+ """ Assemble the navibar
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: navibar html
+ """
+ request = self.request
+ found = {} # pages we found. prevent duplicates
+ items = [] # navibar items
+ item = u'%s'
+ current = d['page_name']
+
+ # Process config navi_bar
+ if request.cfg.navi_bar:
+ for text in request.cfg.navi_bar:
+ pagename, link = self.splitNavilink(text)
+ if pagename == current:
+ cls = 'wikilink current'
+ else:
+ cls = 'wikilink'
+ items.append(item % (cls, link))
+ found[pagename] = 1
+
+ # Add current page at end of local pages
+ if not current in found:
+ title = d['page'].split_title()
+ title = self.shortenPagename(title)
+ link = d['page'].link_to(request, title)
+ cls = 'current'
+ items.append(item % (cls, link))
+
+ # Assemble html
+ items = u''.join(items)
+ html = u'''
+
+''' % items
+ return html
+
+
+
def wikipanel(self, d):
""" Create wiki panel """
_ = self.request.getText
From 77b2d49c58905521c2d3f7758c07696506af8d82 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Tue, 25 Feb 2014 18:00:23 +0100
Subject: [PATCH 29/52] munin: no diskstat plugin si iscsi
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Car ça fait maaaaassssss graphes à tracer en plus, dyson souffre.
---
munin/scripts/link_plugins.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/munin/scripts/link_plugins.py b/munin/scripts/link_plugins.py
index 41626328..a79dd34a 100755
--- a/munin/scripts/link_plugins.py
+++ b/munin/scripts/link_plugins.py
@@ -22,6 +22,9 @@ import tempfile
from hosts_plugins import hosts_plugins, general_plugins
+from gestion.config.services import services
+
+
# Plugins munin classiques à ignorer
IGNORE_PLUGINS = (
'apt_all',
@@ -39,6 +42,13 @@ IGNORE_PLUGINS = (
'vlan_',
)
+if socket.gethostname() in services.services.get('iscsi', []):
+ IGNORE_PLUGINS += (
+ 'diskstat',
+ 'diskstats',
+ 'diskstat_',
+ )
+
# Chemin d'accès aux plugins munin
MUNIN_PATH = "/usr/share/munin/plugins"
From 52f65a152b3a6a71851fad8ca22e9eb979b02259 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Tue, 25 Feb 2014 18:02:09 +0100
Subject: [PATCH 30/52] services.py dans config
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
C'est un lien depuis /etc/crans/ mais c'est chiant de manipuler le path, du
coup…
---
gestion/config/services.py | 1 +
1 file changed, 1 insertion(+)
create mode 120000 gestion/config/services.py
diff --git a/gestion/config/services.py b/gestion/config/services.py
new file mode 120000
index 00000000..d53deb22
--- /dev/null
+++ b/gestion/config/services.py
@@ -0,0 +1 @@
+/etc/crans/services.py
\ No newline at end of file
From e0f16edf28ed7d743c6711f19aecbf4b35c75b86 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Wed, 26 Feb 2014 00:33:54 +0100
Subject: [PATCH 31/52] radius: (wip) enregistrement mac
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Quand une machine se connecte pour la première fois, et qu'elle a une mac auto
on enregistre la vraie, et on trigger generate sur komaz.
---
freeradius/auth.py | 85 ++++++++++++++++++++++++++++++++++++----------
freeradius/test.py | 9 +++--
2 files changed, 75 insertions(+), 19 deletions(-)
diff --git a/freeradius/auth.py b/freeradius/auth.py
index f45aa9af..8ffcbd80 100644
--- a/freeradius/auth.py
+++ b/freeradius/auth.py
@@ -19,12 +19,14 @@
# Voir des exemples plus complets ici:
# https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/
-from lc_ldap.shortcuts import with_ldap_conn, lc_ldap_anonymous
+from lc_ldap.shortcuts import with_ldap_conn, lc_ldap_admin
from lc_ldap.crans_utils import escape as escape_ldap
+import lc_ldap.crans_utils
from gestion.config.config import vlans
import lc_ldap.objets
import radiusd
import netaddr
+from gestion.gen_confs.generate import trigger as trigger_generate
# Voilà , pour faire marcher le V6Only, il faut se retirer l'ipv4 de sa machine
# ou en enregistrer une nouvelle (sans ipv4) avec une autre mac. Moi j'ai la
@@ -41,6 +43,10 @@ bl_isolement = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
# TODO LOGSSSSS
bl_accueil = [u'carte_etudiant', u'chambre_invalide', u'paiement']
+# Decorateur utilisé plus tard (same connection)
+use_ldap = with_ldap_conn(retries=2, delay=5, constructor=lc_ldap_admin)
+
+@use_ldap
def get_machines(auth_data, conn):
mac = None
username = None
@@ -49,18 +55,40 @@ def get_machines(auth_data, conn):
# Calling-Station-Id: "une_adresse_mac"
for (key, value) in auth_data:
if key == 'Calling-Station-Id':
- mac = escape_ldap(value.decode('ascii', 'ignore').replace('"',''))
+ try:
+ value = value.decode('ascii', 'ignore').replace('"','')
+ mac = lc_ldap.crans_utils.format_mac(value)
+ except:
+ radiusd.radlog(radiusd.L_ERR, 'Cannot format MAC !')
if key == 'User-Name':
username = escape_ldap(value.decode('ascii', 'ignore').replace('"',''))
+
# TODO
- # format mac (done by preprocess & hints)
# format username (strip .wifi.crans.org)
base = u'(objectclass=machine)'
- # Search by reported mac, then (if failure) search by username (mac or host)
- return conn.search(u'(&%s(macAddress=%s))' % (base, mac)) or \
- conn.search(u'(&%s(|(macAddress=%s)(host=%s.wifi.crans.org)))' %
- (base, username, username))
+
+ if mac is None:
+ radiusd.radlog(radiusd.L_ERR, 'Cannot read client MAC from AP !')
+ return []
+
+ mac = escape_ldap(mac)
+ username = escape_ldap(username)
+
+ search_strats = [
+ # Case 1: Search by mac (reported by AP)
+ u'(&%s(macAddress=%s))' % (base, mac),
+ # Case 2: unregistered mac
+ u'(&%s(macAddress=)(host=%s.wifi.crans.org))' %
+ (base, username),
+ ]
+
+ for filter_s in search_strats:
+ res = conn.search(filter_s, mode='rw')
+ if res:
+ break
+
+ return res
def get_prise(auth_data):
"""Extrait la prise"""
@@ -91,8 +119,25 @@ def get_prise(auth_data):
if bat_num and bat_name and port:
return bat_name + "%01d%02d" % (bat_num, port)
-# Decorateur utilisé plus tard (same connection)
-use_ldap = with_ldap_conn(retries=2, delay=5, constructor=lc_ldap_anonymous)
+
+@use_ldap
+def register_mac(auth_data, machine, conn):
+ for (key, value) in auth_data:
+ if key == 'Calling-Station-Id':
+ try:
+ value = value.decode('ascii', 'ignore').replace('"','')
+ mac = lc_ldap.crans_utils.format_mac(value)
+ except:
+ radiusd.radlog(radiusd.L_ERR, 'Cannot format MAC !')
+ if mac is not None:
+ mac = unicode(mac.lower())
+ machine['macAddress'] = mac
+ machine.history_add(u'auth.py', u'macAddress ( %s )' % mac)
+ machine.save()
+ radiusd.radlog(radiusd.L_INFO, 'Mac set')
+ trigger_generate('komaz', background=True)
+ else:
+ radiusd.radlog(radiusd.L_ERR, 'Cannot find MAC')
@use_ldap
def instantiate(p, conn):
@@ -108,15 +153,20 @@ def wifi_authorize(auth_data, conn):
champs login et mot de passe qui serviront ensuite à l'authentification
(MschapV2/PEAP ou MschapV2/TTLS)"""
- items = get_machines(auth_data, conn)
+ items = get_machines(auth_data)
if not items:
radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Nobody found')
return radiusd.RLM_MODULE_NOTFOUND
+
if len(items) > 1:
- radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Too many results')
+ radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Too many results (took first)')
machine = items[0]
+
+ if '' in machine['macAddress']:
+ register_mac(auth_data, machine)
+
proprio = machine.proprio()
if isinstance(proprio, lc_ldap.objets.AssociationCrans):
@@ -131,8 +181,10 @@ def wifi_authorize(auth_data, conn):
radiusd.radlog(radiusd.L_ERR, 'WiFi authentication but machine has no' +
'password')
return radiusd.RLM_MODULE_REJECT
+
password = machine['ipsec'][0].value.encode('ascii', 'ignore')
+ # TODO: feed cert here
return (radiusd.RLM_MODULE_UPDATED,
(),
(
@@ -150,7 +202,7 @@ def post_auth(auth_data, conn):
reason = ''
identity = "" #TODO
prise = "" #TODO
- items = get_machines(auth_data, conn)
+ items = get_machines(auth_data)
decision = 'adherent',''
if not items:
@@ -162,7 +214,6 @@ def post_auth(auth_data, conn):
if isinstance(machine, lc_ldap.objets.machineWifi):
decision = 'wifi', ''
- print machine['macAddress'][0].value
if not machine['ipHostNumber'] or unicode(machine['macAddress'][0]) in test_v6:
decision = 'v6only', 'No IPv4'
elif machine['ipHostNumber'][0].value in netaddr.IPNetwork('10.2.9.0/24'):
@@ -171,14 +222,14 @@ def post_auth(auth_data, conn):
for bl in machine.blacklist_actif():
if bl.value['type'] in bl_isolement:
- decision = 'isolement', unicode(bl).encode('utf-8')
+ decision = 'isolement', unicode(bl)
if bl.value['type'] in bl_accueil:
- decision = 'accueil', unicode(bl).encode('utf-8')
+ decision = 'accueil', unicode(bl)
vlan_name, reason = decision
vlan = vlans[vlan_name]
radiusd.radlog(radiusd.L_INFO, 'auth.py: %s -> %s [%s%s]' %
- (prise, identity, vlan_name, (reason and ': ' + reason))
+ (prise, identity, vlan_name, (reason and u': ' + reason).encode(u'utf-8'))
)
#
@@ -198,7 +249,7 @@ def post_auth(auth_data, conn):
# return (0, "Hébergeur non à jour", "accueil")
#
#
-
+ return radiusd.RLM_MODULE_OK
return (radiusd.RLM_MODULE_UPDATED,
(
("Tunnel-Type", "VLAN"),
diff --git a/freeradius/test.py b/freeradius/test.py
index 1cc5472f..c3467794 100755
--- a/freeradius/test.py
+++ b/freeradius/test.py
@@ -5,12 +5,17 @@ import auth
import sys
import time
-if len(sys.argv) < 2:
+if len(sys.argv) < 2 and False:
print "Give me a mac !"
sys.exit(1)
# Machine à s'authentifier (cerveaulent)
-p=(('Calling-Station-Id', sys.argv[1]),)
+#p=(('Calling-Station-Id', sys.argv[1]),)
+
+p=(
+ ('Calling-Station-Id', 'ba:27:eb:3c:54:d5'),
+ ('User-Name', 'test18'),
+)
print repr(auth.wifi_authorize(p))
print "wait for 3s, tu peux aller crasher le serveur pg ou ldap"
From 2224da31e9bec9f3b04cd972f80f4cd76e5e289e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pierre-Elliott=20B=C3=A9cue?=
Date: Wed, 26 Feb 2014 00:55:26 +0100
Subject: [PATCH 32/52] [nolslib] Typo
---
gestion/iscsi/nolslib.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/gestion/iscsi/nolslib.py b/gestion/iscsi/nolslib.py
index f04440f7..f7677fc8 100644
--- a/gestion/iscsi/nolslib.py
+++ b/gestion/iscsi/nolslib.py
@@ -3,7 +3,7 @@
# baie_lib.py
# ----------
-# Type à taper si ça chie : Pierre-Elliott Bécue
+# Type à taper si ça chie : Pierre-Elliott Bécue
# Licence : WTFPL
'''Bibliothèque pour accéder à la baie de stockage nols, récupère les données
@@ -113,7 +113,7 @@ class Nols(object):
Objects = tree.findall("OBJECT")
#Objects = tree.findall("OBJECT[@name='volume-view']")
##Â Fin cf juste en dessous
-
+
for Object in Objects:
name = None
lun = None
@@ -121,7 +121,7 @@ class Nols(object):
# la merde que j'ai fait juste après.
#name = Object.findall("PROPERTY[@name='volume-name']")[0].text
#lun = Object.findall("OBJECT/PROPERTY[@name='lun']")[0].text
-
+
######## Début merde que j'ai faite juste après ###########
if not (Object.attrib['name'] == "volume-view"):
pass
@@ -178,5 +178,5 @@ class Nols(object):
def rename_volume(self, origin_name, new_name):
'''Renomme un volume.'''
-
- self.cmd("set volume name %s %s" % (new_name, orig_name))
+
+ self.cmd("set volume name %s %s" % (new_name, origin_name))
From a3715746cffe665468bbae1c8effe0b5b4243578 Mon Sep 17 00:00:00 2001
From: Vincent Le Gallic
Date: Fri, 28 Feb 2014 08:13:29 +0100
Subject: [PATCH 33/52] =?UTF-8?q?[wiki/macro]=20Ajout=20d'une=20macro=20po?=
=?UTF-8?q?ur=20montrer=20toutes=20les=20pages=20qui=20ont=20des=20ACL=20s?=
=?UTF-8?q?p=C3=A9cifi=C3=A9es.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
wiki/macro/AllPagesWithACL.py | 53 +++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 wiki/macro/AllPagesWithACL.py
diff --git a/wiki/macro/AllPagesWithACL.py b/wiki/macro/AllPagesWithACL.py
new file mode 100644
index 00000000..dd3c48f1
--- /dev/null
+++ b/wiki/macro/AllPagesWithACL.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+"""
+ MoinMoin - AllPagesWithACL Macro
+
+ @copyright: 2007 Alexander "Loki" Agibalov
+ @license: GNU GPL, see COPYING for details.
+
+ changes:
+ 12.2007 - conversion to new syntax by Bolesław Kulbabiński
+"""
+
+import os
+import re
+from MoinMoin.Page import Page
+from MoinMoin import wikiutil
+
+def getAcl(request, pagename):
+ pg = Page(request, pagename)
+ pi = pg.get_pi()
+ ret = pi["acl"].getString()
+ if ret == '':
+ ret = "not defined"
+ return ret
+
+
+def macro_AllPagesWithACL(macro, args):
+ html = "All pages:
"
+ all = {}
+ pages = macro.request.rootpage.getPageList()
+# pages = macro.request.rootpage.getPageList(filter = re.compile("^WikiSandBox").match)
+ html += "Total: %s pages
" % str(len(pages))
+
+ for pagename in pages:
+ all[Page(macro.request, pagename).link_to(macro.request)] = getAcl(macro.request, pagename)
+
+ html += ""
+ all1 = sorted(all.items())
+ for pg, ac in all1:
+ html += "%s | " % pg
+ html += "%s |
" % ac
+ html += "
"
+
+ return macro.formatter.rawHTML(html)
+
+
+def execute(macro, args):
+ try:
+ return wikiutil.invoke_extension_function(
+ macro.request, macro_AllPagesWithACL, args, [macro])
+ except ValueError, err:
+ return macro.request.formatter.text(
+ "<>" % err.args[0])
+
From 4f3c2120e0e6dafb0ebb6718bf5e537e19b06677 Mon Sep 17 00:00:00 2001
From: Vincent Le Gallic
Date: Fri, 28 Feb 2014 08:14:39 +0100
Subject: [PATCH 34/52] [wiki/macro] On n'affiche pas les acl vides ni les
pages moinmoin
---
wiki/macro/AllPagesWithACL.py | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/wiki/macro/AllPagesWithACL.py b/wiki/macro/AllPagesWithACL.py
index dd3c48f1..8fc04e9f 100644
--- a/wiki/macro/AllPagesWithACL.py
+++ b/wiki/macro/AllPagesWithACL.py
@@ -7,6 +7,12 @@
changes:
12.2007 - conversion to new syntax by Bolesław Kulbabiński
+
+ Modifié par Vincent Le Galli
+ (cf http://moinmo.in/MacroMarket/1.6_AdminTools)
+ * patch pour ne pas afficher les acl "not defined"
+ * Si on fournit le paramètre IncludeSystemPages, on a aussi les pages MoinMoin,
+ mais par défaut, non.
"""
import os
@@ -31,13 +37,15 @@ def macro_AllPagesWithACL(macro, args):
html += "Total: %s pages
" % str(len(pages))
for pagename in pages:
- all[Page(macro.request, pagename).link_to(macro.request)] = getAcl(macro.request, pagename)
+ if Page(macro.request,pagename).isStandardPage() or (args != None and "IncludeSystemPages" in args):
+ all[Page(macro.request, pagename).link_to(macro.request)] = getAcl(macro.request, pagename)
html += ""
all1 = sorted(all.items())
for pg, ac in all1:
- html += "%s | " % pg
- html += "%s |
" % ac
+ if ac != "not defined":
+ html += "%s | " % pg
+ html += "%s |
" % ac
html += "
"
return macro.formatter.rawHTML(html)
From b47b1174d4cde2ed92f79e64e99b3d28c3170ff4 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Fri, 28 Feb 2014 19:38:34 +0100
Subject: [PATCH 35/52] radius_auth: ancien CROUS sur vlan 10
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Ceci est une solution temporaire en attendant qu'ils viennent adhérer.
---
utils/radius_auth.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/utils/radius_auth.py b/utils/radius_auth.py
index 4e636e18..885e8bcc 100755
--- a/utils/radius_auth.py
+++ b/utils/radius_auth.py
@@ -51,6 +51,12 @@ def do_auth(mac, prise):
conn = crans_ldap(readonly=True)
m = conn.search('mac=%s' % mac)['machine']
if len(m) == 0:
+ # Est-ce un ancien client de l'offre Crous ?
+ # on le met sur le vlan install-party où on aura activé un forwarding
+ # (uniquement en attendant qu'il soit inscrit proprement)
+ for chbre in annuaires_pg.reverse(prise[0], prise[1:]):
+ if not annuaires_pg.is_crans(prise[0], chbre):
+ return (0, "TMP: ancien client CROUS", 'event')
return (0, "Mac inconnue", "accueil")
elif len(m) > 1:
return (-1, "Pb recherche mac (nb résultat %d!=1)" % len(m), "")
From 2da409cf8cafcbec47674e4e33af9922cf3cc3e4 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Fri, 28 Feb 2014 23:23:39 +0100
Subject: [PATCH 36/52] =?UTF-8?q?generate:=20trigger=20dans=20un=20fichier?=
=?UTF-8?q?=20=C3=A0=20part?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
**Eye of the trigger**
---
gestion/gen_confs/generate.py | 21 +--------------------
gestion/gen_confs/trigger.py | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+), 20 deletions(-)
create mode 100755 gestion/gen_confs/trigger.py
diff --git a/gestion/gen_confs/generate.py b/gestion/gen_confs/generate.py
index c6c7eed3..40765c7c 100755
--- a/gestion/gen_confs/generate.py
+++ b/gestion/gen_confs/generate.py
@@ -15,7 +15,7 @@ arguments peuvent être founis pour une même option, les séparer par &
"""
import sys, signal, os, getopt
-import subprocess
+from trigger import trigger_generate as trigger
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, hostname
@@ -31,25 +31,6 @@ openlog("generate")
db = crans_ldap()
make_lock('auto_generate', 'Big lock', nowait=1)
-def trigger(host, background=False):
- if not 'adm.crans.org' in host:
- host=host + '.adm.crans.org'
- options = ['PasswordAuthentication=no', 'ConnectTimeout=1', 'VerifyHostKeyDNS=yes',
- 'BatchMode=yes', 'ServerAliveInterval=5', 'ServerAliveCountMax=1']
- args = ["ssh", "-4", "-i", "/etc/crans/secrets/trigger-generate" ]
- for opt in options:
- args.append('-o')
- args.append(opt)
- args.extend(["rpcssh@%s" % host, "generate"])
- if background:
- subprocess.Popen(args)
- else:
- p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- out, err = p.communicate()
- if err:
- raise Exception(err)
- return out
-
class base_reconfigure:
try:
sys.path.append('/etc/crans/')
diff --git a/gestion/gen_confs/trigger.py b/gestion/gen_confs/trigger.py
new file mode 100755
index 00000000..29c565af
--- /dev/null
+++ b/gestion/gen_confs/trigger.py
@@ -0,0 +1,24 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import subprocess
+
+def trigger_generate(host, background=False):
+ if not 'adm.crans.org' in host:
+ host=host + '.adm.crans.org'
+ options = ['PasswordAuthentication=no', 'ConnectTimeout=1', 'VerifyHostKeyDNS=yes',
+ 'BatchMode=yes', 'ServerAliveInterval=5', 'ServerAliveCountMax=1']
+ args = ["ssh", "-4", "-i", "/etc/crans/secrets/trigger-generate" ]
+ for opt in options:
+ args.append('-o')
+ args.append(opt)
+ args.extend(["rpcssh@%s" % host, "generate"])
+ if background:
+ subprocess.Popen(args)
+ else:
+ p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ if err:
+ raise Exception(err)
+ return out
+
From c95de3f7c06e4c7b9b496a057ff223ef1ad84c4f Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Fri, 28 Feb 2014 23:27:16 +0100
Subject: [PATCH 37/52] secrets: sys.argv peut ne pas exister
Du coup on fait gaffe.
---
gestion/secrets_new.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gestion/secrets_new.py b/gestion/secrets_new.py
index bb9961dc..1706db34 100644
--- a/gestion/secrets_new.py
+++ b/gestion/secrets_new.py
@@ -31,7 +31,7 @@ import getpass
def get(secret):
""" Recupere un secret. """
openlog('secrets_new')
- prog = os.path.basename(sys.argv[0])
+ prog = os.path.basename(getattr(sys, 'argv', ['undefined'])[0])
syslog('%s (in %s) asked for %s' % (getpass.getuser(), prog, secret))
try:
f = open("/etc/crans/secrets/" + secret)
From c43b94c187e1ba748050f76927f4990f63986b5e Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Sat, 1 Mar 2014 00:11:38 +0100
Subject: [PATCH 38/52] =?UTF-8?q?[populate=5FsshFingerprint]=20=C3=89critu?=
=?UTF-8?q?re=20sur=20la=20base=20ldap=20dans=20un=20context,=20style=20pl?=
=?UTF-8?q?us=20l=C3=A9ger?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/populate_sshFingerprint.py | 30 +++++++++++---------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/gestion/gen_confs/populate_sshFingerprint.py b/gestion/gen_confs/populate_sshFingerprint.py
index 3b32d4b4..b3fb7042 100755
--- a/gestion/gen_confs/populate_sshFingerprint.py
+++ b/gestion/gen_confs/populate_sshFingerprint.py
@@ -57,10 +57,11 @@ def ssh_keygen(algo,size):
print("Nouvelle clef %s générée" % key_path)
def get_machines():
- machines=[]
+ filter=""
for ip in set(ip4_addresses()):
- machines.extend(conn.search(u'ipHostNumber=%s' % ip, mode='rw'))
- return machines
+ filter+=u'(ipHostNumber=%s)' % ip
+ filter = u"(|%s)" % filter
+ return conn.search(filter, mode='rw')
def check_keys_age(key_path,algo):
age=time.time()-os.path.getmtime(key_path)
@@ -74,22 +75,25 @@ def get_local_keys():
key_path='/etc/ssh/ssh_host_%s_key.pub' % algo
if os.path.isfile(key_path):
check_keys_age(key_path,algo)
- keys[algo]=open(key_path).read()
+ keys[algo]=unicode(open(key_path).read().strip())
return keys
def check_keys(keys):
return dict([ (algo,key.split()[1] == ssh_keyscan('localhost',algo)) for algo,key in keys.items() ])
-
-def publish_keys():
+
+def valid_keys():
keys=get_local_keys()
validation=check_keys(keys)
- machines=get_machines()
- for machine in machines:
- sshkeys_old=[str(key) for key in machine.get('sshFingerprint',[])]
- sshkeys_new=[key.decode('UTF-8') for algo,key in keys.items() if validation[algo]]
- if not set(sshkeys_old)==set(sshkeys_new):
- machine['sshFingerprint']=sshkeys_new
- machine.save()
+ return [key for algo,key in keys.items() if validation[algo]]
+
+def publish_keys():
+ keys=valid_keys()
+ for machine in get_machines():
+ with machine:
+ if machine['sshFingerprint'] != keys:
+ print "Key list changed"
+ machine['sshFingerprint'] = keys
+ machine.save()
if __name__ == '__main__' :
From b372b52c7674d5a25dd2409fffae289bf4d44bdd Mon Sep 17 00:00:00 2001
From: Vincent Le Gallic
Date: Sat, 1 Mar 2014 07:16:53 +0100
Subject: [PATCH 39/52] =?UTF-8?q?[mkhome]=20for=E2=80=A6else=20ne=20fait?=
=?UTF-8?q?=20pas=20ce=20qu'on=20pense?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Du coup le message d'Usage s'affichait tout le temps.
---
gestion/tools/mkhome.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/gestion/tools/mkhome.py b/gestion/tools/mkhome.py
index abc4af68..a348ff38 100755
--- a/gestion/tools/mkhome.py
+++ b/gestion/tools/mkhome.py
@@ -11,6 +11,9 @@ import services
if not 'crans-nfs' in services.services or not socket.gethostname() in services.services['crans-nfs']:
sys.stderr.write("Devrait être exécuté sur une machine du groupe 'crans-nfs'\n")
exit(1)
+if len(sys.argv) < 1:
+ sys.stderr.write("Usage : %s [user1] [user2] [user3] ...\n" % sys.argv[0])
+ exit(1)
import lc_ldap.shortcuts
import gestion.gen_confs.adherents
@@ -23,9 +26,6 @@ for user in sys.argv[1:]:
if a and a[0]['homeDirectory'] and a[0]['uidNumber'] and a[0]['uid']:
l.append("%s,%s,%s" % (a[0]['homeDirectory'][0], a[0]['uidNumber'][0], a[0]['uid'][0]))
-else:
- sys.stderr.write("Usage : %s [user1] [user2] [user3] ...\n" % sys.argv[0])
if l:
h=gestion.gen_confs.adherents.home(l)
h.reconfigure()
-
From d5bd1ec23e5e61ca501718195ea718607a89b2fe Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sat, 1 Mar 2014 20:17:31 +0100
Subject: [PATCH 40/52] =?UTF-8?q?radius:=20on=20se=20d=C3=A9barasse=20du?=
=?UTF-8?q?=20fils=20ssh?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Et on a presque un truc qui marche.
Bon le trigger_generate, on va vite le virer parce que c'est mauche tout de
même.
---
freeradius/auth.py | 41 ++++++++++++++++++++++++++++--------
freeradius/test.py | 10 ++++++---
gestion/gen_confs/trigger.py | 23 +++++++++++++++-----
3 files changed, 57 insertions(+), 17 deletions(-)
diff --git a/freeradius/auth.py b/freeradius/auth.py
index 8ffcbd80..1e39d449 100644
--- a/freeradius/auth.py
+++ b/freeradius/auth.py
@@ -19,14 +19,15 @@
# Voir des exemples plus complets ici:
# https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/
-from lc_ldap.shortcuts import with_ldap_conn, lc_ldap_admin
+import lc_ldap.shortcuts
from lc_ldap.crans_utils import escape as escape_ldap
import lc_ldap.crans_utils
from gestion.config.config import vlans
import lc_ldap.objets
import radiusd
import netaddr
-from gestion.gen_confs.generate import trigger as trigger_generate
+import traceback
+from gestion.gen_confs.trigger import trigger_generate_cochon as trigger_generate
# Voilà , pour faire marcher le V6Only, il faut se retirer l'ipv4 de sa machine
# ou en enregistrer une nouvelle (sans ipv4) avec une autre mac. Moi j'ai la
@@ -37,6 +38,15 @@ u'dc:9f:db:5c:c3:ea', # polynice-wlan0
u'00:26:c7:a6:9e:16', # cerveaulent
]
+# TODO (Ã metre dans bcfg2)
+#setfacl -m u:freerad:rx /etc/crans/
+#setfacl -m u:freerad:rx /etc/crans/secrets
+#setfacl -m u:freerad:r /etc/crans/secrets/dhcp.py
+#setfacl -m u:freerad:r /etc/crans/secrets/secrets.py
+#setfacl -m u:freerad:r /etc/crans/secrets/trigger-generate.pub
+#setfacl -m m::r /etc/crans/secrets/trigger-generate
+#setfacl -m u:freerad:r /etc/crans/secrets/trigger-generate
+
bl_reject = [u'bloq']
bl_isolement = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
# TODO carte_etudiant: dépend si sursis ou non (regarder lc_ldap)
@@ -44,7 +54,10 @@ bl_isolement = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
bl_accueil = [u'carte_etudiant', u'chambre_invalide', u'paiement']
# Decorateur utilisé plus tard (same connection)
-use_ldap = with_ldap_conn(retries=2, delay=5, constructor=lc_ldap_admin)
+use_ldap_admin = lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5,
+ constructor=lc_ldap.shortcuts.lc_ldap_admin)
+use_ldap = lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5,
+ constructor=lc_ldap.shortcuts.lc_ldap_anonymous)
@use_ldap
def get_machines(auth_data, conn):
@@ -84,7 +97,7 @@ def get_machines(auth_data, conn):
]
for filter_s in search_strats:
- res = conn.search(filter_s, mode='rw')
+ res = conn.search(filter_s)
if res:
break
@@ -120,8 +133,9 @@ def get_prise(auth_data):
return bat_name + "%01d%02d" % (bat_num, port)
-@use_ldap
+@use_ldap_admin
def register_mac(auth_data, machine, conn):
+ machine = conn.search(unicode(machine.dn.split(',',1)[0]), mode='rw')[0]
for (key, value) in auth_data:
if key == 'Calling-Station-Id':
try:
@@ -129,19 +143,25 @@ def register_mac(auth_data, machine, conn):
mac = lc_ldap.crans_utils.format_mac(value)
except:
radiusd.radlog(radiusd.L_ERR, 'Cannot format MAC !')
+
if mac is not None:
mac = unicode(mac.lower())
+
+ radiusd.radlog(radiusd.L_INFO, 'Registering mac %s' % mac)
machine['macAddress'] = mac
- machine.history_add(u'auth.py', u'macAddress ( %s )' % mac)
+ machine.history_add(u'auth.py', u'macAddress ( -> %s)' % mac)
machine.save()
radiusd.radlog(radiusd.L_INFO, 'Mac set')
- trigger_generate('komaz', background=True)
+ radiusd.radlog(radiusd.L_INFO, 'Triggering komaz')
+ trigger_generate('komaz')
+ radiusd.radlog(radiusd.L_INFO, 'done ! (triggered komaz)')
else:
radiusd.radlog(radiusd.L_ERR, 'Cannot find MAC')
+@use_ldap_admin
@use_ldap
-def instantiate(p, conn):
- """Utile pour initialiser la connexion ldap une première fois (otherwise,
+def instantiate(p, *conns):
+ """Utile pour initialiser les connexions ldap une première fois (otherwise,
do nothing)"""
pass
@@ -249,7 +269,10 @@ def post_auth(auth_data, conn):
# return (0, "Hébergeur non à jour", "accueil")
#
#
+ # Pour l'instant, on ne met pas d'infos de vlans dans la réponse
return radiusd.RLM_MODULE_OK
+
+ # This is dead code (for now)
return (radiusd.RLM_MODULE_UPDATED,
(
("Tunnel-Type", "VLAN"),
diff --git a/freeradius/test.py b/freeradius/test.py
index c3467794..4d5e7365 100755
--- a/freeradius/test.py
+++ b/freeradius/test.py
@@ -5,13 +5,17 @@ import auth
import sys
import time
-if len(sys.argv) < 2 and False:
- print "Give me a mac !"
- sys.exit(1)
+delattr(sys, 'argv')
+
+#if len(sys.argv) < 2 and False:
+# print "Give me a mac !"
+# sys.exit(1)
# Machine à s'authentifier (cerveaulent)
#p=(('Calling-Station-Id', sys.argv[1]),)
+auth.instantiate(())
+
p=(
('Calling-Station-Id', 'ba:27:eb:3c:54:d5'),
('User-Name', 'test18'),
diff --git a/gestion/gen_confs/trigger.py b/gestion/gen_confs/trigger.py
index 29c565af..8da9b110 100755
--- a/gestion/gen_confs/trigger.py
+++ b/gestion/gen_confs/trigger.py
@@ -3,16 +3,22 @@
import subprocess
-def trigger_generate(host, background=False):
+_options = ['PasswordAuthentication=no', 'ConnectTimeout=1', 'VerifyHostKeyDNS=yes',
+ 'BatchMode=yes', 'ServerAliveInterval=5', 'ServerAliveCountMax=1']
+_args = ["ssh", "-4", "-i", "/etc/crans/secrets/trigger-generate" ]
+
+def build_args(host):
if not 'adm.crans.org' in host:
host=host + '.adm.crans.org'
- options = ['PasswordAuthentication=no', 'ConnectTimeout=1', 'VerifyHostKeyDNS=yes',
- 'BatchMode=yes', 'ServerAliveInterval=5', 'ServerAliveCountMax=1']
- args = ["ssh", "-4", "-i", "/etc/crans/secrets/trigger-generate" ]
- for opt in options:
+ args = list(_args)
+ for opt in _options:
args.append('-o')
args.append(opt)
args.extend(["rpcssh@%s" % host, "generate"])
+ return args
+
+def trigger_generate(host, background=False):
+ args = build_args(host)
if background:
subprocess.Popen(args)
else:
@@ -22,3 +28,10 @@ def trigger_generate(host, background=False):
raise Exception(err)
return out
+def trigger_generate_cochon(host):
+ """Ceci est une fonction crade qui permet de se débarraser du process enfant
+ que l'on aurait laissé en arrière plan"""
+ args = build_args(host)
+ p = subprocess.Popen(['/bin/bash'],
+ stdin=subprocess.PIPE, )
+ p.communicate(' '.join(args) + ' &> /dev/null &')
From 4564c6ece2398f6e125ccf9f08ed44cb5f048381 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sat, 1 Mar 2014 22:00:54 +0100
Subject: [PATCH 41/52] radius/auth.py: contexte pour modifier la mac
---
freeradius/auth.py | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/freeradius/auth.py b/freeradius/auth.py
index 1e39d449..39deccc5 100644
--- a/freeradius/auth.py
+++ b/freeradius/auth.py
@@ -135,7 +135,6 @@ def get_prise(auth_data):
@use_ldap_admin
def register_mac(auth_data, machine, conn):
- machine = conn.search(unicode(machine.dn.split(',',1)[0]), mode='rw')[0]
for (key, value) in auth_data:
if key == 'Calling-Station-Id':
try:
@@ -144,9 +143,11 @@ def register_mac(auth_data, machine, conn):
except:
radiusd.radlog(radiusd.L_ERR, 'Cannot format MAC !')
- if mac is not None:
- mac = unicode(mac.lower())
-
+ if mac is None:
+ radiusd.radlog(radiusd.L_ERR, 'Cannot find MAC')
+ return
+ mac = unicode(mac.lower())
+ with conn.search(unicode(machine.dn.split(',',1)[0]), mode='rw')[0] as machine:
radiusd.radlog(radiusd.L_INFO, 'Registering mac %s' % mac)
machine['macAddress'] = mac
machine.history_add(u'auth.py', u'macAddress ( -> %s)' % mac)
@@ -155,8 +156,6 @@ def register_mac(auth_data, machine, conn):
radiusd.radlog(radiusd.L_INFO, 'Triggering komaz')
trigger_generate('komaz')
radiusd.radlog(radiusd.L_INFO, 'done ! (triggered komaz)')
- else:
- radiusd.radlog(radiusd.L_ERR, 'Cannot find MAC')
@use_ldap_admin
@use_ldap
From 8c2165030d900f5b35ae8dc65acada88195bd264 Mon Sep 17 00:00:00 2001
From: Daniel STAN
Date: Sun, 2 Mar 2014 02:08:53 +0100
Subject: [PATCH 42/52] =?UTF-8?q?freeradius:=20m=C3=A0j=20ipv6=20quand=20o?=
=?UTF-8?q?n=20enregistre=20la=20mac?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
freeradius/auth.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/freeradius/auth.py b/freeradius/auth.py
index 39deccc5..a4f23a2f 100644
--- a/freeradius/auth.py
+++ b/freeradius/auth.py
@@ -151,6 +151,7 @@ def register_mac(auth_data, machine, conn):
radiusd.radlog(radiusd.L_INFO, 'Registering mac %s' % mac)
machine['macAddress'] = mac
machine.history_add(u'auth.py', u'macAddress ( -> %s)' % mac)
+ machine.validate_changes()
machine.save()
radiusd.radlog(radiusd.L_INFO, 'Mac set')
radiusd.radlog(radiusd.L_INFO, 'Triggering komaz')
From b04ab576da5d4967e926cb20281f50f22faf1de2 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 10:55:30 +0100
Subject: [PATCH 43/52] [gestion/affich_tools] Support des couleurs dans dialog
---
gestion/affich_tools.py | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/gestion/affich_tools.py b/gestion/affich_tools.py
index 2682e57d..d2652395 100755
--- a/gestion/affich_tools.py
+++ b/gestion/affich_tools.py
@@ -74,7 +74,7 @@ def dialog(backtitle,arg,dialogrc='') :
elif not result : result=['']
return [ 0, result ]
-def coul(txt, col=None):
+def coul(txt, col=None, dialog=False):
"""
Retourne la chaine donnée encadrée des séquences qui
vont bien pour obtenir la couleur souhaitée
@@ -92,6 +92,21 @@ def coul(txt, col=None):
'cyan': 36,
'gris': 30,
'gras': 50 }
+ codecol_dialog = {
+ 'rouge': 1,
+ 'vert': 2,
+ 'jaune': 3,
+ 'bleu': 4,
+ 'violet': 5,
+ 'cyan': 6,
+ 'gris': 0,
+ 'gras': 'b' }
+
+ if dialog:
+ try:
+ txt = "\Z%s%s\Zn" % (codecol_dialog[col], txt)
+ finally:
+ return txt
try:
if col[:2] == 'f_':
add = 10
@@ -128,7 +143,7 @@ def cprint(txt, col='blanc', newline=True):
else:
print t,
-def tableau(data, titre=None, largeur=None, alignement=None, format=None):
+def tableau(data, titre=None, largeur=None, alignement=None, format=None, dialog=False):
"""
Retourne une chaine formatée repésentant un tableau.
@@ -183,9 +198,11 @@ def tableau(data, titre=None, largeur=None, alignement=None, format=None):
# Largeurs
##########
if not largeur :
- largeur = [ max([len(re.sub('\x1b\[1;([0-9]|[0-9][0-9])m','',ligne[i])) for ligne in data]) for i in range(nbcols) ]
+ largeur = [ max([len(re.sub('\\\Z.' if dialog else '\x1b\[1;([0-9]|[0-9][0-9])m','',ligne[i])) for ligne in data]) for i in range(nbcols) ]
elif '*' in largeur:
rows, cols = get_screen_size()
+ if dialog:
+ cols = cols - 6
for i in range(nbcols) :
if largeur[i] in ['*',-1] :
largeur[i] = max(cols - sum([l for l in largeur if l != '*']) - nbcols - 1, 3)
@@ -198,12 +215,12 @@ def tableau(data, titre=None, largeur=None, alignement=None, format=None):
def aligne (data, alignement, largeur) :
# Longeur sans les chaines de formatage
- l = len(re.sub('\x1b\[1;([0-9]|[0-9][0-9])m','',data))
+ l = len(re.sub('\\\Z.' if dialog else '\x1b\[1;([0-9]|[0-9][0-9])m','',data))
# Alignement
if l > largeur :
# découpage d'une chaine trop longue
- regexp = re.compile('\x1b\[1;([0-9]|[0-9][0-9])m')
+ regexp = re.compile('\\\Z.' if dialog else '\x1b\[1;([0-9]|[0-9][0-9])m')
new_data = u''
new_len = 0
From 6603476e2f45d768eab14043f2d737ef5252e0a1 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:15:16 +0100
Subject: [PATCH 44/52] =?UTF-8?q?[bind]=20Mise=20=C3=A0=20jour=20des=20DS?=
=?UTF-8?q?=20pour=20les=20sous=20zones=20de=20crans.org?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/bind.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/gestion/gen_confs/bind.py b/gestion/gen_confs/bind.py
index 7d20d025..d0d75667 100755
--- a/gestion/gen_confs/bind.py
+++ b/gestion/gen_confs/bind.py
@@ -458,10 +458,10 @@ class dns(gen_config) :
# /!\ Il faut faire attention au rollback des keys, il faudrait faire quelque chose d'automatique avec opendnssec
DSs = {
'crans.org': [
- DS('adm','565 8 2 498f6cd5bcf291aae4129700a7569fa6e9a86821185bd655f0b9efc6a3bf547e'),
- DS('ferme','35156 8 2 b63a1443b3d7434429e879e046bc8ba89056cdcb4b9c3566853e64fd521895b8'),
- DS('wifi','41320 8 2 024799c1d53f1e827f03d17bc96709b85ee1c05d77eb0ebeadcfbe207ee776a4'),
- DS('tv','30910 8 2 3317f684081867ab94402804fbb3cd187e29655cc7f34cb92c938183fe0b71f5'),
+ DS('adm', '64649 8 2 9c45f0fef063672d96c983d5a3813a08a649c72d357f41ddece73ae8872d60cf'),
+ DS('ferme', '57424 8 2 2c21ec2a80a9ceb93fe085409ebdbab8d39145c18dc8ea8b23e9a38b5c414eb4'),
+ DS('wifi', '5531 8 2 daf30a647566234edc1617546fd74abbbaf965b17389248f72fc66a33d6f5063'),
+ DS('tv', '18199 8 2 d3cc2f5f81b830cbb8894ffd32c236e968edd3b0c0305112b6eb970aa763418e'),
],
}
From 6efe6f8a98aabb7426c6b0d6bc2438c8c1ce0f6a Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:15:56 +0100
Subject: [PATCH 45/52] =?UTF-8?q?[bind]=20commit=20identit=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/bind.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/gestion/gen_confs/bind.py b/gestion/gen_confs/bind.py
index d0d75667..1529dfa1 100755
--- a/gestion/gen_confs/bind.py
+++ b/gestion/gen_confs/bind.py
@@ -160,7 +160,7 @@ class ZoneBase(object):
def __init__(self, zone_name):
self._rrlist=[]
self.zone_name = zone_name
-
+
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.zone_name)
@@ -198,8 +198,8 @@ class ZoneClone(ZoneBase):
self.add(rr)
if rr._name in ["%s." % self.zone_clone.zone_name]:
self.add(ResourceRecord(rr._type, "%s." % self.zone_name, rr._value))
-
-
+
+
class Zone(ZoneBase):
def __init__(self, zone_name, ttl, soa, ns_list, ipv6=True, ipv4=True, other_zones=[]):
super(Zone, self).__init__(zone_name)
@@ -307,7 +307,7 @@ class Zone(ZoneBase):
if alias in ['@', '%s.' % self.zone_name]:
self.add_a_record(alias, machine)
self.add_aaaa_record(alias, machine)
- self.add_sshfp_record(alias, machine)
+ self.add_sshfp_record(alias, machine)
elif to_zone == self.zone_name:
self.add(CNAME(alias, "%s" % to_nom))
if self.ipv4 and self.ipv6:
@@ -315,7 +315,7 @@ class Zone(ZoneBase):
self.add(CNAME("%s.v6" % alias, "%s.v6" % to_nom))
else:
self.add(CNAME(alias, "%s." % machine['host'][0]))
-
+
class ZoneReverse(Zone):
def __init__(self, net, ttl, soa, ns_list):
@@ -337,7 +337,7 @@ class ZoneReverse(Zone):
def reverse(net, ip=None):
"""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 si elle est fournie, n'importe
+ mettre dans le fichier de zone si elle est fournie, n'importe
quoi sinon."""
n = netaddr.IPNetwork(net)
a = netaddr.IPAddress(ip if ip else n.ip)
@@ -445,7 +445,7 @@ class dns(gen_config) :
SRV('sips', 'tcp', 5, 0, 5061, 'asterisk'),
]
}
- NATPRs = {
+ NATPRs = {
'crans.org' : [
NAPTR('@', 5, 100, "S", "SIPS+D2T", "", '_sips._tcp.crans.org.', ttl=86400),
NAPTR('@', 10, 100, "S", "SIP+D2U", "", '_sip._udp.crans.org.', ttl=86400),
From e84817213b0ee7c401e813cb8ff735d3625f72e3 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:16:28 +0100
Subject: [PATCH 46/52] [config/dns, bind] Remplacement de ovh par soyouz
---
gestion/config/config_srv.py | 2 +-
gestion/config/dns.py | 4 ++--
gestion/gen_confs/bind.py | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/gestion/config/config_srv.py b/gestion/config/config_srv.py
index 7b65dc1d..ba560fc9 100644
--- a/gestion/config/config_srv.py
+++ b/gestion/config/config_srv.py
@@ -5,4 +5,4 @@
adm_only = []
-role = {'zamok': ['adherents-server'], 'nat64': ['routeur-nat64'], 'komaz': ['wifi-router', 'appt-proxy', 'main-router'], 'dyson': ['sniffer'], 'isc': ['appt-proxy'], 'dhcp': ['appt-proxy'], 'ovh': ['externe'], 'routeur': ['appt-proxy']}
+role = {'zamok': ['adherents-server'], 'nat64': ['routeur-nat64'], 'komaz': ['wifi-router', 'appt-proxy', 'main-router'], 'dyson': ['sniffer'], 'isc': ['appt-proxy'], 'dhcp': ['appt-proxy'], 'ovh': ['externe'], 'soyouz': ['externe'], 'routeur': ['appt-proxy']}
diff --git a/gestion/config/dns.py b/gestion/config/dns.py
index e92de589..8382d1ad 100644
--- a/gestion/config/dns.py
+++ b/gestion/config/dns.py
@@ -30,8 +30,8 @@ zone_tv = 'tv.crans.org'
#: DNS en connexion de secours
secours_relay='10.231.136.14';
-#: Serveurs authoritaires pour les zones crans, le master doit être le premier
-DNSs = ['sable.crans.org', 'freebox.crans.org', 'ovh.crans.org']
+#: Serveurs autoritaires pour les zones crans, le master doit être le premier
+DNSs = ['sable.crans.org', 'freebox.crans.org', 'soyouz.crans.org']
#: Résolution DNS directe, liste de toutes les zones crans hors reverse
zones_direct = [ 'crans.org', 'crans.ens-cachan.fr', 'wifi.crans.org', 'ferme.crans.org' , 'clubs.ens-cachan.fr', 'adm.crans.org','crans.eu','wifi.crans.eu', 'tv.crans.org', 'ap.crans.org' ]
diff --git a/gestion/gen_confs/bind.py b/gestion/gen_confs/bind.py
index 1529dfa1..062b90a1 100755
--- a/gestion/gen_confs/bind.py
+++ b/gestion/gen_confs/bind.py
@@ -432,7 +432,7 @@ class dns(gen_config) :
# format : [ priorité serveur , .... ]
MXs = [
MX('@',10, 'redisdead.crans.org.'),
- MX('@',20, 'ovh.crans.org.'),
+ MX('@',15, 'soyouz.crans.org.'),
MX('@',25, 'freebox.crans.org.'),
]
SRVs = {
From 987c56a0822e044c9e9c4219e02965be170b1507 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:17:51 +0100
Subject: [PATCH 47/52] [firewall4] Proxy ARP pour soyouz
---
gestion/gen_confs/firewall4/base.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gestion/gen_confs/firewall4/base.py b/gestion/gen_confs/firewall4/base.py
index e36ecf81..1844378c 100644
--- a/gestion/gen_confs/firewall4/base.py
+++ b/gestion/gen_confs/firewall4/base.py
@@ -24,7 +24,7 @@ class firewall(utils.firewall_tools) :
def __init__(self):
super(firewall, self).__init__()
-
+
self.reloadable = {
'blacklist_hard' : self.blacklist_hard,
'test_mac_ip' : self.test_mac_ip,
@@ -175,6 +175,11 @@ class firewall(utils.firewall_tools) :
self.add(table, chain, '-m mac -s %s --mac-source %s -j RETURN' % (ip_ovh, config.mac_komaz))
self.add(table, chain, '-m mac -s %s --mac-source %s -j RETURN' % (ip_ovh, config.mac_titanic))
+ # Proxy ARP de Komaz et Titanic pour OVH
+ ip_soyouz = self.conn.search(u"host=soyouz.adm.crans.org")[0]['ipHostNumber'][0]
+ self.add(table, chain, '-m mac -s %s --mac-source %s -j RETURN' % (ip_soyouz, config.mac_komaz))
+ self.add(table, chain, '-m mac -s %s --mac-source %s -j RETURN' % (ip_soyouz, config.mac_titanic))
+
self.add(table, chain, '-j REJECT')
print OK
From 5ca8dee0906ed6174067357a6c7158fa20f4d48f Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:18:13 +0100
Subject: [PATCH 48/52] =?UTF-8?q?[tv/radio]=20Mise=20=C3=A0=20jour=20des?=
=?UTF-8?q?=20url=20pour=20les=20radios=20Armitunes=20et=20Rire=20et=20Cha?=
=?UTF-8?q?nson?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
tv/radio/config.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tv/radio/config.py b/tv/radio/config.py
index aa8346c9..5a05683f 100644
--- a/tv/radio/config.py
+++ b/tv/radio/config.py
@@ -7,7 +7,7 @@ def dir(path):
return l
multicast={
'Radio': {
- 'Armitunes': ('armitunes','239.231.140.162','1234',['http://149.255.33.76:8004/','http://95.31.11.136:9010/','http://95.31.3.225:9010/','http://hanyo.dyndns-server.com:9078/']),
+ 'Armitunes': ('armitunes','239.231.140.162','1234',['http://198.27.80.17:8000/','http://95.31.11.136:9010/','http://95.31.3.225:9010/']),
'Radio Classique': ('classique','239.231.140.163','1234',['http://broadcast.infomaniak.net:80/radioclassique-high.mp3']),
'France Inter': ('inter','239.231.140.164','1234',['http://mp3.live.tv-radio.com/franceinter/all/franceinterhautdebit.mp3']),
'France Info': ('info','239.231.140.165','1234',['http://mp3.live.tv-radio.com/franceinfo/all/franceinfo-32k.mp3']),
@@ -16,7 +16,7 @@ multicast={
# 'Webradio Rock': ('rock','239.231.140.168','1234',['http://webradio.crans.org:8000/rock.mp3']),
'I.ACTIVE DANCE': ('iactive','239.231.140.170', '1234', ['http://serveur.wanastream.com:48700/']),
'Skyrock': ('skyrock', '239.231.140.171', '1234', ['http://95.81.146.6/3665/sky_122353.mp3']),
- 'Rire et Chanson': ('rireetchanson', '239.231.140.172', '1234', ['http://95.81.146.2/rire_et_chansons/all/rir_124629.mp3']),
+ 'Rire et Chanson': ('rireetchanson', '239.231.140.172', '1234', ['http://95.81.146.10/5011/nrj_122230.mp3']),
'Europe 1': ('europe1', '239.231.140.173', '1234', ['http://vipicecast.yacast.net/europe1.mp3']),
'Chérie FM': ('cherie_fm', '239.231.140.174', '1234', ['http://95.81.146.2/cherie_fm/all/che_124310.mp3']),
'France Culture': ('culture', '239.231.140.175', '1234', ['http://95.81.147.3/franceculture/all/franceculturehautdebit.mp3']),
From 8962c3b33dc714cac2c2236856375ecbf4d8ca5d Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:19:55 +0100
Subject: [PATCH 49/52] =?UTF-8?q?[gitignore]=20Ajout=20de=20deux=20module?=
=?UTF-8?q?=20tier,=20un=20qui=20d=C3=A9crit=20le=20format=20de=20certific?=
=?UTF-8?q?at=20binaire,=20et=20un=20pythondialog=20am=C3=A9lior=C3=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.gitignore b/.gitignore
index 6b67b4cd..59081440 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,10 @@ var/
surveillance/mac_prises/output/
doc/build/
+# modules tier
+pyasn1_modules/
+pythondialog/
+
# etat_* de la connexion de secours
secours/etat_*
From 21341577a581893a5158fdd55a780a2f3047e761 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:22:20 +0100
Subject: [PATCH 50/52] =?UTF-8?q?[gestion]=20Ajout=20d'un=20d=C3=A9but=20d?=
=?UTF-8?q?e=20gest=5Fcrans=20utilisant=20lc=5Fldap?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gest_crans_lc.py | 305 +++++++++++++++++++++++++++++++++++++++
1 file changed, 305 insertions(+)
create mode 100755 gestion/gest_crans_lc.py
diff --git a/gestion/gest_crans_lc.py b/gestion/gest_crans_lc.py
new file mode 100755
index 00000000..0bf6bb84
--- /dev/null
+++ b/gestion/gest_crans_lc.py
@@ -0,0 +1,305 @@
+#!/bin/bash /usr/scripts/python.sh
+# -*- coding: utf-8 -*-
+
+u"""
+Interface utilisateur du système de gestion des machines
+et adhérents du crans
+
+Copyright (C) Valentin Samir
+Licence : GPLv3
+
+"""
+import os
+import sys
+import signal
+from pythondialog import Dialog
+
+from gestion.affich_tools import get_screen_size, coul
+
+import lc_ldap.shortcuts
+import lc_ldap.printing as printing
+
+def handle_exit_code(d, code):
+ if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
+ if code == d.DIALOG_CANCEL:
+ msg = "Vous avez choisi Annuler dans la dernière fenêtre de dialogue.\n\n" \
+ "Voulez vous quitter le programme ?"
+ os.system('clear')
+ sys.exit(0)
+ else:
+ msg = "Vous avez appuyer sur ESC dans la dernière fenêtre de dialogue.\n\n" \
+ "Voulez vous quitter le programme ?"
+ if d.yesno(msg, width=60) == d.DIALOG_OK:
+ os.system('clear')
+ sys.exit(0)
+ return False
+ else:
+ return True # code est d.DIALOG_OK
+
+
+
+def search(dialog, objectClassS, title, values={}):
+ """
+ Rechercher des adhérents ou des machines dans la base ldap
+ retourne le tuple (code de retour dialog, valeurs entrée par l'utilisateur, liste d'objets trouvés)
+ La fonction est découpé en trois partie :
+ * affichage dialog et récupération du résultat
+ * construction de filtres de recherche ldap et recherches ldap
+ * filtre sur les résultats des recherches ldap
+ """
+ select_dict = {
+ #label attribut ldap search for substring param dialog: line col valeur input-line icol len max-chars
+ 'Nom' : {'ldap':'nom', 'sub':True, 'params' : [ 1, 1, values.get('nom', ""), 1, 13, 20, 20]},
+ 'Prenom' : {'ldap':'prenom', 'sub':True, 'params' : [ 2, 1, values.get('prenom', ""), 2, 13, 20, 20]},
+ 'Téléphone' : {'ldap':'tel', 'sub':True, 'params' : [ 3, 1, values.get('tel', ""), 3, 13, 10, 00]},
+ 'Chambre' : {'ldap':'chbre','sub':True, 'params' : [ 4, 1, values.get('chbre',""), 4, 13, 05, 00]},
+ 'aid' : {'ldap' : 'aid', 'sub':False, 'params' : [ 5, 1, values.get('aid',""), 5, 13, 05, 05]},
+ 'mail' : {'ldap' : 'mail', 'sub':True, 'params' : [ 6, 1, values.get('mail',""), 6, 13, 20, 00]},
+ # seconde colone
+ 'Machine' : {'ldap' : '*', 'sub':True, 'params' : [1, 35, "", 1, 43, 0, 0]},
+ 'Host' : {'ldap' : 'host', 'sub':True, 'params' : [2, 37, values.get('host',""), 2, 43, 17, 17]},
+ 'Mac' : {'ldap' : 'macAddress', 'sub':False, 'params' : [3, 37, values.get('macAddress',""), 3, 43, 17, 17]},
+ 'IP' : {'ldap' : 'ipHostNumber', 'sub':False,'params' : [4, 37, values.get('ipHostNumber',""), 4, 43, 15, 15]},
+ 'mid' : {'ldap' : 'mid', 'sub':False, 'params' : [5, 37, values.get('mid',""), 5, 43, 5, 5]},
+ }
+ # On a besoin de l'ordre pour récupérer les valeurs ensuite
+ select_adherent = ['Nom', 'Prenom', 'Téléphone', 'Chambre', 'aid', 'mail']
+ select_machine = ['Host', 'Mac', 'IP', 'mid']
+ def box():
+ # On met les argument à dialog à la main ici, sinon, c'est difficile de choisir comment mettre une seconde colone
+ cmd = ["--form", "Entrez vos paramètres de recherche", '0', '0', '0']
+ for key in select_adherent:
+ cmd.extend(['%s :' % key] + [str(e) for e in select_dict[key]['params']])
+ cmd.extend(['Machine :'] + [str(e) for e in select_dict['Machine']['params']])
+ for key in select_machine:
+ cmd.extend(['%s :' % key] + [str(e) for e in select_dict[key]['params']])
+ cmd.extend(["Les champs vides sont ignorés.", '7', '1', "", '0', '0', '0', '0'])
+ # On utilise quand même la fonction de la bibliothèques pour passer les arguments
+ (code, output) = dialog._perform(*(cmd,), title=title, backtitle="Entrez vos paramètres de recherche")
+ if output:
+ return (code, output.split('\n')[:-1])
+ else: # empty selection
+ return (code, [])
+
+ (code, dialog_values) = box()
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ return code, values, []
+ else:
+ # Transformation de la liste des valeures entrée en dictionnnaire
+ dialog_values = dict(zip(select_adherent + select_machine, dialog_values))
+ ldap_values = dict([(select_dict[key]['ldap'], value) for key, value in dialog_values.items()])
+
+ # Construction des filtres ldap pour les adhérents et les machines
+ filter_adherent = []
+ filter_machine = []
+ for (key, value) in dialog_values.items():
+ if value:
+ if key in select_adherent:
+ filter_adherent.append((u"(%s=*%s*)" if select_dict[key]['sub'] else u"(%s=%s)") % (select_dict[key]['ldap'], unicode(value, 'utf-8')))
+ elif key in select_machine:
+ filter_machine.append((u"(%s=*%s*)" if select_dict[key]['sub'] else u"(%s=%s)") % (select_dict[key]['ldap'], unicode(value, 'utf-8')))
+ if filter_adherent:
+ filter_adherent=u"(&%s)" % "".join(filter_adherent)
+ if filter_machine:
+ filter_machine=u"(&%s)" % "".join(filter_machine)
+
+ # Récupération des adhérents et des machines
+ adherents=conn.search(filter_adherent) if filter_adherent else []
+ machines=conn.search(filter_machine) if filter_machine else []
+
+ # Filtrage des machines en fonction des adhérents
+ if filter_adherent:
+ if filter_machine:
+ # Si on filtre sur des adhérent et des machines, on calcule l'intersection
+ adherents_dn = set([a.dn for a in adherents])
+ machines_f = [m for m in machines if m.parent_dn in adherents_dn]
+ else:
+ # Sinon on filtre seulement sur les adhérents, récupère les machines des adhérents trouvés
+ machines_f = [m for a in adherents for m in a.machines()]
+ else:
+ # Sinon si on filtre seulement sur des machines
+ machines_f = machines
+
+ # Filtrage des adhérents en fonction des machines
+ if filter_machine:
+ if filter_adherent:
+ # Si on filtre sur des adhérents et des machines, on calcule l'intersection
+ machines_dn = set([m.parent_dn for m in machines])
+ adherents_f = [a for a in adherents if a.dn in machines_dn]
+ else:
+ # Sinon on récupères les proprios des machines trouvées
+ adherents_f = [m.proprio() for m in machines]
+ else:
+ # Sinon si on filtre seulement sur des adhérents
+ adherents_f = adherents
+
+ # On filtre sur les objectClassS
+ return code, ldap_values, [ o for objectClass in objectClassS for o in machines_f+adherents_f if objectClass in o['objectClass'] ]
+
+def select_one(dialog, items, default_item=None):
+ """Fait selectionner un item parmis une liste d'items à l'utisateur"""
+ ### TODO afficher correctement les objets dans items
+ choices=[]
+ count = 0
+ default_tag = items.index(default_item) if default_item in items else default_item
+ for i in items:
+ choices.append((str(count), str(i), 1 if default_tag == count else 0))
+ count+=1
+ tag=''
+ while not tag:
+ (line, col) = get_screen_size()
+ (code, tag) = dialog.radiolist(
+ "Choisir",
+ choices=choices,
+ default_item=str(default_tag),
+ width=col-4,
+ height=line-3,
+ list_height=line-3,
+ scrollbar=True)
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ return code, None
+ if not tag:
+ dialog.msgbox("Merci de choisir l'un des item de la liste ou d'annuler", title="Sélection", width=0, height=0)
+ return code, items[int(tag)]
+
+def select_confirm(dialog, item, title):
+ """Affiche un item et demande si c'est bien celui là que l'on veux (supprimer, éditer, créer,...)"""
+ return dialog.yesno(printing.sprint(item), no_collapse=True, colors=True, title=title, width=0, height=0, backtitle="Appuyez sur MAJ pour selectionner du texte") == dialog.DIALOG_OK
+
+def select(dialog, objectClassS, title, values={}):
+ """Permet de choisir un objet adhérent ou machine dans la base ldap"""
+ while True:
+ try:
+ # On fait effectuer une recherche à l'utilisateur
+ code, values, items = search(dialog, objectClassS, title, values)
+ # Si il a appuyé sur annuler ou sur escape, on annule
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ return code, None
+ # S'il n'y a pas de résultas, on recommence
+ elif not items:
+ dialog.msgbox("Aucun Résultat", title="Recherche", width=0, height=0)
+ # S'il y a plusieurs résultats
+ elif len(items)>1:
+ item = None
+ while True:
+ # On en fait choisir un
+ code, item = select_one(dialog, items, item)
+ # Si il à appuyer sur annuler ou sur escape, on recommence la recherche
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ break
+ # Sinon, on fait confirmer son choix à l'utilisateur
+ elif select_confirm(dialog, item, title):
+ return code, item
+ # S'il y a exactement 1 résultat à la recherche, on fait confirmer son choix à l'utilisateur
+ elif len(items) == 1 and select_confirm(dialog, items[0], title):
+ return code, items[0]
+ except Exception as e:
+ dialog.msgbox("%r" % e, title="Erreur rencontrée", width=0, height=0)
+
+def modif_adherent(dialog):
+ code, adherent = select(dialog, ["adherent"], "Recherche d'un adhérent")
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ return code
+ dialog.msgbox("todo", width=0, height=0)
+
+def create_adherent(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+def delete_adherent(dialog):
+ code, adherent = select(dialog, ["adherent"], "Recherche d'un adhérent")
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ return code
+ dialog.msgbox("todo", width=0, height=0)
+
+def modif_machine(dialog):
+ code, machine = select(dialog, ["machineFixe", "machineWifi", "machineCrans", "borneWifi"], "Recherche d'une machine")
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ return code
+ dialog.msgbox("todo", width=0, height=0)
+
+def create_machine_adherent(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+def delete_machine(dialog):
+ code, machine = select(dialog, ["machineFixe", "machineWifi", "machineCrans", "borneWifi"], "Recherche d'une machine")
+ if code in (dialog.DIALOG_CANCEL, dialog.DIALOG_ESC):
+ return code
+ dialog.msgbox("todo", width=0, height=0)
+
+
+def create_club(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+
+def delete_club(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+def modif_club(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+def create_machine_club(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+def create_machine_crans(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+def create_borne(dialog):
+ dialog.msgbox("todo", width=0, height=0)
+
+def menu_principal(dialog):
+ menu = {
+ 'aA' : {'text':"Inscrire un nouvel adhérent", 'callback': create_adherent},
+ 'mA' : {'text':"Modifier l'inscription d'un adhérent", 'callback': modif_adherent, 'help':"Changer la chambre, la remarque, la section, la carte d'étudiant ou précâbler."},
+ 'aMA': {'text':"Ajouter une machine à un adhérent", 'callback': create_machine_adherent},
+ 'dA' : {'text':"Détruire un adhérent", 'callback': delete_adherent, 'help':"Suppression de l'adhérent ainsi que de ses machines"},
+ 'mM' : {'text':"Modifier une machine existante", 'callback': modif_machine, 'help':"Changer le nom ou la MAC d'une machine."},
+ 'dM' : {'text':"Détruire une machine", 'callback': delete_machine},
+ 'aC' : {'text':"Inscrire un nouveau club", 'callback': create_club},
+ 'mC' : {'text':"Modifier un club", 'callback': modif_club},
+ 'aMC': {'text':"Ajouter une machine à un club", 'callback': create_machine_club},
+ 'dC' : {'text':"Détruire un club", 'callback': delete_club},
+ 'aKM': {'text':"Ajouter une machine à l'association", 'callback': create_machine_crans},
+ 'aKB': {'text':"Ajouter une borne wifi", 'callback': create_borne},
+ '' : {'text':"---------------------------------------",'callback': lambda x: x},
+ }
+ ### Les clef qui n'existe pas sont toute renvoyé sur la clef ''
+ medu_order = ["aA", "mA", "aMA", "dA", "", "mM", "dM", " ", "aC", "mC", "aMC", "dC", " ", "aKM", "aKB"]
+ def box(default_item=None):
+ return dialog.menu(
+ "Que souhaitez vous faire ?",
+ width=55,
+ height=0,
+ menu_height=15,
+ item_help=1,
+ default_item=str(default_item),
+ title="Menu principal",
+ scrollbar=True,
+ cancel_label="Quitter",
+ backtitle=u"Vous êtes connecté en tant que %s" % conn.current_login,
+ choices=[(key, menu.get(key, menu[''])['text'], menu.get(key, menu['']).get('help', "")) for key in medu_order])
+
+ tag=None
+ while True:
+ (code, tag) = box(tag)
+ if handle_exit_code(dialog, code):
+ menu.get(tag, menu[''])['callback'](dialog)
+
+
+if __name__ == '__main__':
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ # On initialise le moteur de rendu en spécifiant qu'on va faire du dialog
+ printing.template(dialog=True)
+
+ # On ouvre une connexion lc_ldap
+ conn = lc_ldap.shortcuts.lc_ldap_admin()
+ # On vérifie que l'utilisateur système existe dans ldap (pour la gestion des droits)
+ luser=conn.search(u"uid=%s" % conn.current_login)
+ if not luser:
+ sys.stderr.write("L'utilisateur %s n'existe pas dans la base de donnée" % conn.current_login)
+ sys.exit(1)
+ conn.droits = [str(d) for d in luser[0]['droits']]
+ conn.dn = luser[0].dn
+
+ dialog = Dialog()
+ menu_principal(dialog)
+ os.system('clear')
From dd7f399744de54cfa8f42e213690a5220973f54f Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:23:12 +0100
Subject: [PATCH 51/52] [chambres_vides] Les adresses mail finssent maintenant
toute bien par @crans.org
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
et puis, on ne peut pas faire ce test avec un attribut mail mais seulement avec
un str, du coup…
---
gestion/chambres_vides.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/gestion/chambres_vides.py b/gestion/chambres_vides.py
index fdb74c46..1d568e3a 100755
--- a/gestion/chambres_vides.py
+++ b/gestion/chambres_vides.py
@@ -66,8 +66,6 @@ for clandestin in bad_boys_e_s:
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
to = clandestin['mail'][0]
- if not "@" in to:
- to += "@crans.org"
mail = mail_module.generate('demenagement', {"from" : "respbats@crans.org",
"chambre" : exchambre,
"jours" : int(ttl/86400) + 1,
From da59f3dae547452941a8fbcc4cc04556d0e284d8 Mon Sep 17 00:00:00 2001
From: Valentin Samir
Date: Mon, 3 Mar 2014 11:24:21 +0100
Subject: [PATCH 52/52] =?UTF-8?q?[gen=5Fconfs/generate]=20Suppression=20de?=
=?UTF-8?q?=20la=20machine=20pgsql=20(qui=20a=20=C3=A9t=C3=A9=20remplac?=
=?UTF-8?q?=C3=A9=20par=20thot)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gestion/gen_confs/generate.py | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/gestion/gen_confs/generate.py b/gestion/gen_confs/generate.py
index 40765c7c..5ae9bac7 100755
--- a/gestion/gen_confs/generate.py
+++ b/gestion/gen_confs/generate.py
@@ -203,15 +203,6 @@ class owl(base_reconfigure):
from adherents import del_user
self._do(del_user(args))
-class pgsql(base_reconfigure):
- def surveillance_exemptions(self):
- from gen_confs.surveillance import exemptions
- self._do(exemptions())
-
- def surveillance_machines(self):
- from gen_confs.surveillance import machines
- self._do(machines(), self._machines())
-
class thot(base_reconfigure):
def surveillance_exemptions(self):
from gen_confs.surveillance import exemptions