Merge branch 'master' of ssh://git.crans.org/git/usr-scripts
This commit is contained in:
commit
30aab68b86
46 changed files with 1075 additions and 200 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -45,6 +45,10 @@ var/
|
||||||
surveillance/mac_prises/output/
|
surveillance/mac_prises/output/
|
||||||
doc/build/
|
doc/build/
|
||||||
|
|
||||||
|
# modules tier
|
||||||
|
pyasn1_modules/
|
||||||
|
pythondialog/
|
||||||
|
|
||||||
# etat_* de la connexion de secours
|
# etat_* de la connexion de secours
|
||||||
secours/etat_*
|
secours/etat_*
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,15 @@
|
||||||
# Voir des exemples plus complets ici:
|
# Voir des exemples plus complets ici:
|
||||||
# https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/
|
# https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/
|
||||||
|
|
||||||
from lc_ldap.shortcuts import with_ldap_conn, lc_ldap_anonymous
|
import lc_ldap.shortcuts
|
||||||
from lc_ldap.crans_utils import escape as escape_ldap
|
from lc_ldap.crans_utils import escape as escape_ldap
|
||||||
|
import lc_ldap.crans_utils
|
||||||
from gestion.config.config import vlans
|
from gestion.config.config import vlans
|
||||||
import lc_ldap.objets
|
import lc_ldap.objets
|
||||||
import radiusd
|
import radiusd
|
||||||
import netaddr
|
import netaddr
|
||||||
|
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
|
# 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
|
# ou en enregistrer une nouvelle (sans ipv4) avec une autre mac. Moi j'ai la
|
||||||
|
@ -35,12 +38,28 @@ u'dc:9f:db:5c:c3:ea', # polynice-wlan0
|
||||||
u'00:26:c7:a6:9e:16', # cerveaulent
|
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_reject = [u'bloq']
|
||||||
bl_isolement = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
|
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)
|
# TODO carte_etudiant: dépend si sursis ou non (regarder lc_ldap)
|
||||||
# TODO LOGSSSSS
|
# TODO LOGSSSSS
|
||||||
bl_accueil = [u'carte_etudiant', u'chambre_invalide', u'paiement']
|
bl_accueil = [u'carte_etudiant', u'chambre_invalide', u'paiement']
|
||||||
|
|
||||||
|
# Decorateur utilisé plus tard (same connection)
|
||||||
|
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):
|
def get_machines(auth_data, conn):
|
||||||
mac = None
|
mac = None
|
||||||
username = None
|
username = None
|
||||||
|
@ -49,25 +68,100 @@ def get_machines(auth_data, conn):
|
||||||
# Calling-Station-Id: "une_adresse_mac"
|
# Calling-Station-Id: "une_adresse_mac"
|
||||||
for (key, value) in auth_data:
|
for (key, value) in auth_data:
|
||||||
if key == 'Calling-Station-Id':
|
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':
|
if key == 'User-Name':
|
||||||
username = escape_ldap(value.decode('ascii', 'ignore').replace('"',''))
|
username = escape_ldap(value.decode('ascii', 'ignore').replace('"',''))
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
# format mac (done by preprocess & hints)
|
|
||||||
# format username (strip .wifi.crans.org)
|
# format username (strip .wifi.crans.org)
|
||||||
|
|
||||||
base = u'(objectclass=machine)'
|
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))
|
|
||||||
|
|
||||||
# Decorateur utilisé plus tard (same connection)
|
if mac is None:
|
||||||
use_ldap = with_ldap_conn(retries=2, delay=5, constructor=lc_ldap_anonymous)
|
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=<automatique>)(host=%s.wifi.crans.org))' %
|
||||||
|
(base, username),
|
||||||
|
]
|
||||||
|
|
||||||
|
for filter_s in search_strats:
|
||||||
|
res = conn.search(filter_s)
|
||||||
|
if res:
|
||||||
|
break
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
@use_ldap_admin
|
||||||
|
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 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 (<automatique> -> %s)' % mac)
|
||||||
|
machine.validate_changes()
|
||||||
|
machine.save()
|
||||||
|
radiusd.radlog(radiusd.L_INFO, 'Mac set')
|
||||||
|
radiusd.radlog(radiusd.L_INFO, 'Triggering komaz')
|
||||||
|
trigger_generate('komaz')
|
||||||
|
radiusd.radlog(radiusd.L_INFO, 'done ! (triggered komaz)')
|
||||||
|
|
||||||
|
@use_ldap_admin
|
||||||
@use_ldap
|
@use_ldap
|
||||||
def instantiate(p, conn):
|
def instantiate(p, *conns):
|
||||||
"""Utile pour initialiser la connexion ldap une première fois (otherwise,
|
"""Utile pour initialiser les connexions ldap une première fois (otherwise,
|
||||||
do nothing)"""
|
do nothing)"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -79,15 +173,20 @@ def wifi_authorize(auth_data, conn):
|
||||||
champs login et mot de passe qui serviront ensuite à l'authentification
|
champs login et mot de passe qui serviront ensuite à l'authentification
|
||||||
(MschapV2/PEAP ou MschapV2/TTLS)"""
|
(MschapV2/PEAP ou MschapV2/TTLS)"""
|
||||||
|
|
||||||
items = get_machines(auth_data, conn)
|
items = get_machines(auth_data)
|
||||||
|
|
||||||
if not items:
|
if not items:
|
||||||
radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Nobody found')
|
radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Nobody found')
|
||||||
return radiusd.RLM_MODULE_NOTFOUND
|
return radiusd.RLM_MODULE_NOTFOUND
|
||||||
|
|
||||||
if len(items) > 1:
|
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]
|
machine = items[0]
|
||||||
|
|
||||||
|
if '<automatique>' in machine['macAddress']:
|
||||||
|
register_mac(auth_data, machine)
|
||||||
|
|
||||||
|
|
||||||
proprio = machine.proprio()
|
proprio = machine.proprio()
|
||||||
if isinstance(proprio, lc_ldap.objets.AssociationCrans):
|
if isinstance(proprio, lc_ldap.objets.AssociationCrans):
|
||||||
|
@ -102,8 +201,10 @@ def wifi_authorize(auth_data, conn):
|
||||||
radiusd.radlog(radiusd.L_ERR, 'WiFi authentication but machine has no' +
|
radiusd.radlog(radiusd.L_ERR, 'WiFi authentication but machine has no' +
|
||||||
'password')
|
'password')
|
||||||
return radiusd.RLM_MODULE_REJECT
|
return radiusd.RLM_MODULE_REJECT
|
||||||
|
|
||||||
password = machine['ipsec'][0].value.encode('ascii', 'ignore')
|
password = machine['ipsec'][0].value.encode('ascii', 'ignore')
|
||||||
|
|
||||||
|
# TODO: feed cert here
|
||||||
return (radiusd.RLM_MODULE_UPDATED,
|
return (radiusd.RLM_MODULE_UPDATED,
|
||||||
(),
|
(),
|
||||||
(
|
(
|
||||||
|
@ -121,7 +222,7 @@ def post_auth(auth_data, conn):
|
||||||
reason = ''
|
reason = ''
|
||||||
identity = "" #TODO
|
identity = "" #TODO
|
||||||
prise = "" #TODO
|
prise = "" #TODO
|
||||||
items = get_machines(auth_data, conn)
|
items = get_machines(auth_data)
|
||||||
|
|
||||||
decision = 'adherent',''
|
decision = 'adherent',''
|
||||||
if not items:
|
if not items:
|
||||||
|
@ -133,7 +234,6 @@ def post_auth(auth_data, conn):
|
||||||
if isinstance(machine, lc_ldap.objets.machineWifi):
|
if isinstance(machine, lc_ldap.objets.machineWifi):
|
||||||
decision = 'wifi', ''
|
decision = 'wifi', ''
|
||||||
|
|
||||||
print machine['macAddress'][0].value
|
|
||||||
if not machine['ipHostNumber'] or unicode(machine['macAddress'][0]) in test_v6:
|
if not machine['ipHostNumber'] or unicode(machine['macAddress'][0]) in test_v6:
|
||||||
decision = 'v6only', 'No IPv4'
|
decision = 'v6only', 'No IPv4'
|
||||||
elif machine['ipHostNumber'][0].value in netaddr.IPNetwork('10.2.9.0/24'):
|
elif machine['ipHostNumber'][0].value in netaddr.IPNetwork('10.2.9.0/24'):
|
||||||
|
@ -142,14 +242,14 @@ def post_auth(auth_data, conn):
|
||||||
|
|
||||||
for bl in machine.blacklist_actif():
|
for bl in machine.blacklist_actif():
|
||||||
if bl.value['type'] in bl_isolement:
|
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:
|
if bl.value['type'] in bl_accueil:
|
||||||
decision = 'accueil', unicode(bl).encode('utf-8')
|
decision = 'accueil', unicode(bl)
|
||||||
|
|
||||||
vlan_name, reason = decision
|
vlan_name, reason = decision
|
||||||
vlan = vlans[vlan_name]
|
vlan = vlans[vlan_name]
|
||||||
radiusd.radlog(radiusd.L_INFO, 'auth.py: %s -> %s [%s%s]' %
|
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'))
|
||||||
)
|
)
|
||||||
|
|
||||||
#<!>
|
#<!>
|
||||||
|
@ -169,7 +269,10 @@ def post_auth(auth_data, conn):
|
||||||
# return (0, "Hébergeur non à jour", "accueil")
|
# 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,
|
return (radiusd.RLM_MODULE_UPDATED,
|
||||||
(
|
(
|
||||||
("Tunnel-Type", "VLAN"),
|
("Tunnel-Type", "VLAN"),
|
||||||
|
@ -182,14 +285,6 @@ def post_auth(auth_data, conn):
|
||||||
def dummy_fun(p):
|
def dummy_fun(p):
|
||||||
return radiusd.RLM_MODULE_OK
|
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):
|
def detach(p=None):
|
||||||
"""Appelé lors du déchargement du module (enfin, normalement)"""
|
"""Appelé lors du déchargement du module (enfin, normalement)"""
|
||||||
print "*** goodbye from example.py ***"
|
print "*** goodbye from example.py ***"
|
||||||
|
|
|
@ -11,25 +11,27 @@ python crans_wifi {
|
||||||
func_authorize = wifi_authorize
|
func_authorize = wifi_authorize
|
||||||
|
|
||||||
# Renseigne le vlan
|
# Renseigne le vlan
|
||||||
|
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
||||||
mod_post_auth = freeradius.auth
|
mod_post_auth = freeradius.auth
|
||||||
func_post_auth = post_auth
|
func_post_auth = post_auth
|
||||||
|
|
||||||
# Le reste est dumb et inutile
|
# Que faire avant de quitter
|
||||||
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
|
|
||||||
|
|
||||||
mod_detach = freeradius.auth
|
mod_detach = freeradius.auth
|
||||||
func_detach = detach
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,21 @@ import auth
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
delattr(sys, 'argv')
|
||||||
print "Give me a mac !"
|
|
||||||
sys.exit(1)
|
#if len(sys.argv) < 2 and False:
|
||||||
|
# print "Give me a mac !"
|
||||||
|
# sys.exit(1)
|
||||||
|
|
||||||
# Machine à s'authentifier (cerveaulent)
|
# Machine à s'authentifier (cerveaulent)
|
||||||
p=(('Calling-Station-Id', sys.argv[1]),)
|
#p=(('Calling-Station-Id', sys.argv[1]),)
|
||||||
|
|
||||||
|
auth.instantiate(())
|
||||||
|
|
||||||
|
p=(
|
||||||
|
('Calling-Station-Id', 'ba:27:eb:3c:54:d5'),
|
||||||
|
('User-Name', 'test18'),
|
||||||
|
)
|
||||||
|
|
||||||
print repr(auth.wifi_authorize(p))
|
print repr(auth.wifi_authorize(p))
|
||||||
print "wait for 3s, tu peux aller crasher le serveur pg ou ldap"
|
print "wait for 3s, tu peux aller crasher le serveur pg ou ldap"
|
||||||
|
|
|
@ -74,7 +74,7 @@ def dialog(backtitle,arg,dialogrc='') :
|
||||||
elif not result : result=['']
|
elif not result : result=['']
|
||||||
return [ 0, 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
|
Retourne la chaine donnée encadrée des séquences qui
|
||||||
vont bien pour obtenir la couleur souhaitée
|
vont bien pour obtenir la couleur souhaitée
|
||||||
|
@ -92,6 +92,21 @@ def coul(txt, col=None):
|
||||||
'cyan': 36,
|
'cyan': 36,
|
||||||
'gris': 30,
|
'gris': 30,
|
||||||
'gras': 50 }
|
'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:
|
try:
|
||||||
if col[:2] == 'f_':
|
if col[:2] == 'f_':
|
||||||
add = 10
|
add = 10
|
||||||
|
@ -128,7 +143,7 @@ def cprint(txt, col='blanc', newline=True):
|
||||||
else:
|
else:
|
||||||
print t,
|
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.
|
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
|
# Largeurs
|
||||||
##########
|
##########
|
||||||
if not largeur :
|
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:
|
elif '*' in largeur:
|
||||||
rows, cols = get_screen_size()
|
rows, cols = get_screen_size()
|
||||||
|
if dialog:
|
||||||
|
cols = cols - 6
|
||||||
for i in range(nbcols) :
|
for i in range(nbcols) :
|
||||||
if largeur[i] in ['*',-1] :
|
if largeur[i] in ['*',-1] :
|
||||||
largeur[i] = max(cols - sum([l for l in largeur if l != '*']) - nbcols - 1, 3)
|
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) :
|
def aligne (data, alignement, largeur) :
|
||||||
# Longeur sans les chaines de formatage
|
# 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
|
# Alignement
|
||||||
if l > largeur :
|
if l > largeur :
|
||||||
# découpage d'une chaine trop longue
|
# 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_data = u''
|
||||||
new_len = 0
|
new_len = 0
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
""" Pour détecter les gens en chambre invalide, les prévenir, et supprimer leurs machines
|
""" Pour détecter les gens en chambre invalide, les prévenir, et supprimer leurs machines
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
import ldap_crans
|
import lc_ldap.shortcuts
|
||||||
conn = ldap_crans.CransLdap()
|
conn = lc_ldap.shortcuts.lc_ldap_admin()
|
||||||
|
|
||||||
import mail as mail_module
|
import mail as mail_module
|
||||||
import sys
|
import sys
|
||||||
|
@ -39,19 +39,20 @@ delai = config.demenagement_delai
|
||||||
|
|
||||||
# On récupère ceux qui n'ont pas payé cette année
|
# On récupère ceux qui n'ont pas payé cette année
|
||||||
if config.periode_transitoire:
|
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:
|
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()
|
now = time.time()
|
||||||
|
|
||||||
|
|
||||||
to_print = []
|
to_print = []
|
||||||
|
to_error = []
|
||||||
for clandestin in bad_boys_e_s:
|
for clandestin in bad_boys_e_s:
|
||||||
# On cherche la dernière fois qu'il s'est retrouvé en chambre ????
|
# 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
|
# On récupère la date du dernier changement de chambre
|
||||||
# (l'historique est enregistré par ordre chronologique)
|
# (l'historique est enregistré par ordre chronologique)
|
||||||
x = re.match("(.*),.* : chbre \((.*) -> \?\?\?\?\)",l)
|
x = re.match("(.*),.* : chbre \((.*) -> \?\?\?\?\)", str(l))
|
||||||
if x <> None:
|
if x <> None:
|
||||||
kickout_date = x.group(1)
|
kickout_date = x.group(1)
|
||||||
exchambre = x.group(2)
|
exchambre = x.group(2)
|
||||||
|
@ -64,9 +65,7 @@ for clandestin in bad_boys_e_s:
|
||||||
if ttl > 0:
|
if ttl > 0:
|
||||||
if (sendmails and machine_liste != [] or DEBUG) and (ttl >= (delai - 1)*86400 or 0 < ttl <= 86400):
|
if (sendmails and machine_liste != [] or DEBUG) and (ttl >= (delai - 1)*86400 or 0 < ttl <= 86400):
|
||||||
# On lui envoie un mail pour le prévenir
|
# On lui envoie un mail pour le prévenir
|
||||||
to = clandestin.mail()
|
to = clandestin['mail'][0]
|
||||||
if not "@" in to:
|
|
||||||
to += "@crans.org"
|
|
||||||
mail = mail_module.generate('demenagement', {"from" : "respbats@crans.org",
|
mail = mail_module.generate('demenagement', {"from" : "respbats@crans.org",
|
||||||
"chambre" : exchambre,
|
"chambre" : exchambre,
|
||||||
"jours" : int(ttl/86400) + 1,
|
"jours" : int(ttl/86400) + 1,
|
||||||
|
@ -81,16 +80,19 @@ for clandestin in bad_boys_e_s:
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for m in machine_liste:
|
for m in machine_liste:
|
||||||
to_print.append( (clandestin.id(), m.ip(), m.id(), m.nom()) )
|
try:
|
||||||
m2 = conn.search('mid=%s' % m.id(),mode='w')['machine'][0]
|
m2 = conn.search(u'mid=%s' % m['mid'][0],mode='w')[0]
|
||||||
m2.delete('Adherent sans chambre valide depuis %d jours' % delai)
|
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 != []:
|
if to_print != []:
|
||||||
# Il s'est passé quelque chose, donc on envoie un mail
|
# Il s'est passé quelque chose, donc on envoie un mail
|
||||||
# On regarde le plus grand hostname
|
# 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)
|
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
|
message += u"\nListe des machines supprimées pour chambre invalide depuis plus de %s jours :\n" % delai
|
||||||
tiret_line = u"+------+-----------------+------+-%s-+\n" % ("-" * hostnamemaxsize)
|
tiret_line = u"+------+-----------------+------+-%s-+\n" % ("-" * hostnamemaxsize)
|
||||||
message += tiret_line
|
message += tiret_line
|
||||||
|
@ -98,8 +100,24 @@ if to_print != []:
|
||||||
message += tiret_line
|
message += tiret_line
|
||||||
for aid, ip, mid, hostname in to_print:
|
for aid, ip, mid, hostname in to_print:
|
||||||
message += template % (aid, ip, mid, hostname)
|
message += template % (aid, ip, mid, hostname)
|
||||||
|
|
||||||
message += tiret_line
|
message += tiret_line
|
||||||
message += u"\nScore de cette nuit : %s" % (len(to_print))
|
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"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"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
headers += u"X-Mailer: /usr/scripts/gestion/chambres_vides.py\n"
|
headers += u"X-Mailer: /usr/scripts/gestion/chambres_vides.py\n"
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
|
|
||||||
adm_only = []
|
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']}
|
||||||
|
|
|
@ -30,8 +30,8 @@ zone_tv = 'tv.crans.org'
|
||||||
#: DNS en connexion de secours
|
#: DNS en connexion de secours
|
||||||
secours_relay='10.231.136.14';
|
secours_relay='10.231.136.14';
|
||||||
|
|
||||||
#: Serveurs authoritaires pour les zones crans, le master doit être le premier
|
#: Serveurs autoritaires pour les zones crans, le master doit être le premier
|
||||||
DNSs = ['sable.crans.org', 'freebox.crans.org', 'ovh.crans.org']
|
DNSs = ['sable.crans.org', 'freebox.crans.org', 'soyouz.crans.org']
|
||||||
|
|
||||||
#: Résolution DNS directe, liste de toutes les zones crans hors reverse
|
#: 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' ]
|
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' ]
|
||||||
|
|
1
gestion/config/services.py
Symbolic link
1
gestion/config/services.py
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
/etc/crans/services.py
|
|
@ -51,17 +51,18 @@ class ResourceRecord(object):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
class TLSA(ResourceRecord):
|
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
|
name: nom du domaine du certificat
|
||||||
port: port où écoute le service utilisant le certificat
|
port: port où écoute le service utilisant le certificat
|
||||||
proto: udp ou tcp
|
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
|
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
|
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
|
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] == '.':
|
if cert is None and proto == 'tcp' and name[-1] == '.':
|
||||||
try:
|
try:
|
||||||
cert = ssl.get_server_certificate((name[:-1], port), ca_certs='/etc/ssl/certs/ca-certificates.crt')
|
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)
|
raise ValueError("Unable de retrieve cert dynamically: %s" % e)
|
||||||
elif cert is None:
|
elif cert is None:
|
||||||
raise ValueError("cert can only be retrive if proto is tcp and name fqdn")
|
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:
|
if not dercert:
|
||||||
raise ValueError("Impossible de convertir le certificat au format DER %s %s %s\n%s" % (name, port, proto, cert))
|
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:
|
if compat:
|
||||||
super(TLSA, self).__init__(
|
super(TLSA, self).__init__(
|
||||||
'TYPE52',
|
'TYPE52',
|
||||||
|
@ -156,7 +160,7 @@ class ZoneBase(object):
|
||||||
def __init__(self, zone_name):
|
def __init__(self, zone_name):
|
||||||
self._rrlist=[]
|
self._rrlist=[]
|
||||||
self.zone_name = zone_name
|
self.zone_name = zone_name
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s %s>" % (self.__class__.__name__, self.zone_name)
|
return "<%s %s>" % (self.__class__.__name__, self.zone_name)
|
||||||
|
@ -194,8 +198,8 @@ class ZoneClone(ZoneBase):
|
||||||
self.add(rr)
|
self.add(rr)
|
||||||
if rr._name in ["%s." % self.zone_clone.zone_name]:
|
if rr._name in ["%s." % self.zone_clone.zone_name]:
|
||||||
self.add(ResourceRecord(rr._type, "%s." % self.zone_name, rr._value))
|
self.add(ResourceRecord(rr._type, "%s." % self.zone_name, rr._value))
|
||||||
|
|
||||||
|
|
||||||
class Zone(ZoneBase):
|
class Zone(ZoneBase):
|
||||||
def __init__(self, zone_name, ttl, soa, ns_list, ipv6=True, ipv4=True, other_zones=[]):
|
def __init__(self, zone_name, ttl, soa, ns_list, ipv6=True, ipv4=True, other_zones=[]):
|
||||||
super(Zone, self).__init__(zone_name)
|
super(Zone, self).__init__(zone_name)
|
||||||
|
@ -254,17 +258,32 @@ class Zone(ZoneBase):
|
||||||
|
|
||||||
def add_sshfp_record(self, nom, machine):
|
def add_sshfp_record(self, nom, machine):
|
||||||
for sshkey in machine.get('sshFingerprint', []):
|
for sshkey in machine.get('sshFingerprint', []):
|
||||||
algo_txt, key = str(sshkey).split()[:2]
|
try:
|
||||||
algo=config.sshfs_ralgo[algo_txt][1]
|
algo_txt, key = str(sshkey).split()[:2]
|
||||||
for hash in config.sshfp_hash.keys():
|
algo=config.sshfs_ralgo[algo_txt][1]
|
||||||
self.add(SSHFP(nom, hash, algo, key))
|
for hash in config.sshfp_hash.keys():
|
||||||
if self.ipv4 and self.ipv6:
|
self.add(SSHFP(nom, hash, algo, key))
|
||||||
if nom == '@':
|
if self.ipv4 and self.ipv6:
|
||||||
self.add(SSHFP("v4", hash, algo, key))
|
if nom == '@':
|
||||||
self.add(SSHFP("v6", hash, algo, key))
|
self.add(SSHFP("v4", hash, algo, key))
|
||||||
else:
|
self.add(SSHFP("v6", hash, algo, key))
|
||||||
self.add(SSHFP("%s.v4" % nom, hash, algo, key))
|
else:
|
||||||
self.add(SSHFP("%s.v6" % nom, hash, algo, key))
|
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_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):
|
def add_machine(self, machine):
|
||||||
for host in machine['host']:
|
for host in machine['host']:
|
||||||
|
@ -274,6 +293,8 @@ class Zone(ZoneBase):
|
||||||
self.add_a_record(nom, machine)
|
self.add_a_record(nom, machine)
|
||||||
self.add_aaaa_record(nom, machine)
|
self.add_aaaa_record(nom, machine)
|
||||||
self.add_sshfp_record(nom, machine)
|
self.add_sshfp_record(nom, machine)
|
||||||
|
for cert in machine.certificats():
|
||||||
|
self.add_tlsa_record(cert)
|
||||||
|
|
||||||
|
|
||||||
if machine['host']:
|
if machine['host']:
|
||||||
|
@ -286,7 +307,7 @@ class Zone(ZoneBase):
|
||||||
if alias in ['@', '%s.' % self.zone_name]:
|
if alias in ['@', '%s.' % self.zone_name]:
|
||||||
self.add_a_record(alias, machine)
|
self.add_a_record(alias, machine)
|
||||||
self.add_aaaa_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:
|
elif to_zone == self.zone_name:
|
||||||
self.add(CNAME(alias, "%s" % to_nom))
|
self.add(CNAME(alias, "%s" % to_nom))
|
||||||
if self.ipv4 and self.ipv6:
|
if self.ipv4 and self.ipv6:
|
||||||
|
@ -294,7 +315,7 @@ class Zone(ZoneBase):
|
||||||
self.add(CNAME("%s.v6" % alias, "%s.v6" % to_nom))
|
self.add(CNAME("%s.v6" % alias, "%s.v6" % to_nom))
|
||||||
else:
|
else:
|
||||||
self.add(CNAME(alias, "%s." % machine['host'][0]))
|
self.add(CNAME(alias, "%s." % machine['host'][0]))
|
||||||
|
|
||||||
|
|
||||||
class ZoneReverse(Zone):
|
class ZoneReverse(Zone):
|
||||||
def __init__(self, net, ttl, soa, ns_list):
|
def __init__(self, net, ttl, soa, ns_list):
|
||||||
|
@ -316,7 +337,7 @@ class ZoneReverse(Zone):
|
||||||
def reverse(net, ip=None):
|
def reverse(net, ip=None):
|
||||||
"""Renvoie la zone DNS inverse correspondant au réseau et à
|
"""Renvoie la zone DNS inverse correspondant au réseau et à
|
||||||
l'adresse donnés, ainsi que le nombre d'éléments de l'ip a
|
l'adresse donnés, ainsi que le nombre d'éléments de l'ip a
|
||||||
mettre dans le fichier de zone si elle est fournie, n'importe
|
mettre dans le fichier de zone si elle est fournie, n'importe
|
||||||
quoi sinon."""
|
quoi sinon."""
|
||||||
n = netaddr.IPNetwork(net)
|
n = netaddr.IPNetwork(net)
|
||||||
a = netaddr.IPAddress(ip if ip else n.ip)
|
a = netaddr.IPAddress(ip if ip else n.ip)
|
||||||
|
@ -411,7 +432,7 @@ class dns(gen_config) :
|
||||||
# format : [ priorité serveur , .... ]
|
# format : [ priorité serveur , .... ]
|
||||||
MXs = [
|
MXs = [
|
||||||
MX('@',10, 'redisdead.crans.org.'),
|
MX('@',10, 'redisdead.crans.org.'),
|
||||||
MX('@',20, 'ovh.crans.org.'),
|
MX('@',15, 'soyouz.crans.org.'),
|
||||||
MX('@',25, 'freebox.crans.org.'),
|
MX('@',25, 'freebox.crans.org.'),
|
||||||
]
|
]
|
||||||
SRVs = {
|
SRVs = {
|
||||||
|
@ -424,7 +445,7 @@ class dns(gen_config) :
|
||||||
SRV('sips', 'tcp', 5, 0, 5061, 'asterisk'),
|
SRV('sips', 'tcp', 5, 0, 5061, 'asterisk'),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
NATPRs = {
|
NATPRs = {
|
||||||
'crans.org' : [
|
'crans.org' : [
|
||||||
NAPTR('@', 5, 100, "S", "SIPS+D2T", "", '_sips._tcp.crans.org.', ttl=86400),
|
NAPTR('@', 5, 100, "S", "SIPS+D2T", "", '_sips._tcp.crans.org.', ttl=86400),
|
||||||
NAPTR('@', 10, 100, "S", "SIP+D2U", "", '_sip._udp.crans.org.', ttl=86400),
|
NAPTR('@', 10, 100, "S", "SIP+D2U", "", '_sip._udp.crans.org.', ttl=86400),
|
||||||
|
@ -437,10 +458,10 @@ class dns(gen_config) :
|
||||||
# /!\ Il faut faire attention au rollback des keys, il faudrait faire quelque chose d'automatique avec opendnssec
|
# /!\ Il faut faire attention au rollback des keys, il faudrait faire quelque chose d'automatique avec opendnssec
|
||||||
DSs = {
|
DSs = {
|
||||||
'crans.org': [
|
'crans.org': [
|
||||||
DS('adm','565 8 2 498f6cd5bcf291aae4129700a7569fa6e9a86821185bd655f0b9efc6a3bf547e'),
|
DS('adm', '64649 8 2 9c45f0fef063672d96c983d5a3813a08a649c72d357f41ddece73ae8872d60cf'),
|
||||||
DS('ferme','35156 8 2 b63a1443b3d7434429e879e046bc8ba89056cdcb4b9c3566853e64fd521895b8'),
|
DS('ferme', '57424 8 2 2c21ec2a80a9ceb93fe085409ebdbab8d39145c18dc8ea8b23e9a38b5c414eb4'),
|
||||||
DS('wifi','41320 8 2 024799c1d53f1e827f03d17bc96709b85ee1c05d77eb0ebeadcfbe207ee776a4'),
|
DS('wifi', '5531 8 2 daf30a647566234edc1617546fd74abbbaf965b17389248f72fc66a33d6f5063'),
|
||||||
DS('tv','30910 8 2 3317f684081867ab94402804fbb3cd187e29655cc7f34cb92c938183fe0b71f5'),
|
DS('tv', '18199 8 2 d3cc2f5f81b830cbb8894ffd32c236e968edd3b0c0305112b6eb970aa763418e'),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,6 +494,7 @@ class dns(gen_config) :
|
||||||
TLSA('nagios.crans.org.', 443, 'tcp', None, 3, 2),
|
TLSA('nagios.crans.org.', 443, 'tcp', None, 3, 2),
|
||||||
TLSA('pad.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('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('asterisk.crans.org.', 5061, 'tcp', None, 3, 2),
|
||||||
TLSA('smtp.crans.org.', 465, 'tcp', None, 3, 2),
|
TLSA('smtp.crans.org.', 465, 'tcp', None, 3, 2),
|
||||||
TLSA('imap.crans.org.', 993, 'tcp', None, 3, 2),
|
TLSA('imap.crans.org.', 993, 'tcp', None, 3, 2),
|
||||||
|
|
|
@ -36,6 +36,8 @@ class dydhcp:
|
||||||
@raises OmapiError:
|
@raises OmapiError:
|
||||||
@raises socket.error:
|
@raises socket.error:
|
||||||
"""
|
"""
|
||||||
|
if '<automatique>' in [ip, mac]:
|
||||||
|
return
|
||||||
msg = OmapiMessage.open(b"host")
|
msg = OmapiMessage.open(b"host")
|
||||||
msg.message.append((b"create", struct.pack("!I", 1)))
|
msg.message.append((b"create", struct.pack("!I", 1)))
|
||||||
msg.message.append((b"exclusive", struct.pack("!I", 1)))
|
msg.message.append((b"exclusive", struct.pack("!I", 1)))
|
||||||
|
@ -56,6 +58,8 @@ class dydhcp:
|
||||||
@raises OmapiError:
|
@raises OmapiError:
|
||||||
@raises socket.error:
|
@raises socket.error:
|
||||||
"""
|
"""
|
||||||
|
if '<automatique>' in [ip, mac]:
|
||||||
|
return
|
||||||
msg = OmapiMessage.open(b"host")
|
msg = OmapiMessage.open(b"host")
|
||||||
msg.obj.append((b"hardware-address", pack_mac(mac)))
|
msg.obj.append((b"hardware-address", pack_mac(mac)))
|
||||||
msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
|
msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
|
||||||
|
@ -147,7 +151,8 @@ class dhcp(gen_config) :
|
||||||
for machine in self.machines :
|
for machine in self.machines :
|
||||||
self.anim.cycle()
|
self.anim.cycle()
|
||||||
for net in self.reseaux.keys() :
|
for net in self.reseaux.keys() :
|
||||||
if machine.ip() != '<automatique>' and AddrInNet(machine.ip(), net) :
|
if '<automatique>' not in [machine.ip(), machine.mac()] and \
|
||||||
|
AddrInNet(machine.ip(), net):
|
||||||
host_template = self.host_template
|
host_template = self.host_template
|
||||||
# variable pour remplir le template
|
# variable pour remplir le template
|
||||||
#d = { 'nom' : machine.nom().split('.')[0] , 'mac' : machine.mac() , 'ip' : machine.ip() }
|
#d = { 'nom' : machine.nom().split('.')[0] , 'mac' : machine.mac() , 'ip' : machine.ip() }
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import socket
|
import socket
|
||||||
import netaddr
|
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
from utils import pretty_print, anim, OK, cprint
|
from utils import pretty_print, anim, OK, cprint
|
||||||
|
@ -25,7 +24,7 @@ class firewall(utils.firewall_tools) :
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(firewall, self).__init__()
|
super(firewall, self).__init__()
|
||||||
|
|
||||||
self.reloadable = {
|
self.reloadable = {
|
||||||
'blacklist_hard' : self.blacklist_hard,
|
'blacklist_hard' : self.blacklist_hard,
|
||||||
'test_mac_ip' : self.test_mac_ip,
|
'test_mac_ip' : self.test_mac_ip,
|
||||||
|
@ -96,7 +95,7 @@ class firewall(utils.firewall_tools) :
|
||||||
# for ip in ip_list:
|
# for ip in ip_list:
|
||||||
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
|
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
|
||||||
# # Est-ce qu'il y a des blacklists hard parmis les blacklists de la machine
|
# # 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)
|
# try: self.ipset['blacklist']['hard'].add(ip)
|
||||||
# except IpsetError: pass
|
# except IpsetError: pass
|
||||||
# else:
|
# else:
|
||||||
|
@ -110,17 +109,9 @@ class firewall(utils.firewall_tools) :
|
||||||
chain = 'BLACKLIST_HARD'
|
chain = 'BLACKLIST_HARD'
|
||||||
|
|
||||||
if fill_ipset:
|
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
|
# On récupère la liste de toutes les ips blacklistés hard
|
||||||
bl_hard_ips = set(
|
bl_hard_ips = self.blacklisted_ips(config.blacklist_sanctions, config.NETs['all'])
|
||||||
str(ip) for ips in
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
|
||||||
[
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
|
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
|
||||||
print OK
|
print OK
|
||||||
|
|
||||||
|
@ -137,6 +128,8 @@ class firewall(utils.firewall_tools) :
|
||||||
def test_mac_ip_dispatch(self, func, machine):
|
def test_mac_ip_dispatch(self, func, machine):
|
||||||
"""Détermine à quel set de mac-ip appliquer la fonction ``func`` (add, delete, append, ...)"""
|
"""Détermine à quel set de mac-ip appliquer la fonction ``func`` (add, delete, append, ...)"""
|
||||||
ips = machine['ipHostNumber']
|
ips = machine['ipHostNumber']
|
||||||
|
if '<automatique>' in machine['macAddress'] :
|
||||||
|
return
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
# Si la machines est sur le réseau des adhérents
|
# Si la machines est sur le réseau des adhérents
|
||||||
if utils.AddrInNet(str(ip), config.NETs['wifi']):
|
if utils.AddrInNet(str(ip), config.NETs['wifi']):
|
||||||
|
@ -182,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_komaz))
|
||||||
self.add(table, chain, '-m mac -s %s --mac-source %s -j RETURN' % (ip_ovh, config.mac_titanic))
|
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')
|
self.add(table, chain, '-j REJECT')
|
||||||
print OK
|
print OK
|
||||||
|
|
||||||
|
@ -210,6 +208,8 @@ class firewall_routeur(firewall):
|
||||||
def test_mac_ip_dispatch(self, func, machine):
|
def test_mac_ip_dispatch(self, func, machine):
|
||||||
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
|
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
|
||||||
ips = machine['ipHostNumber']
|
ips = machine['ipHostNumber']
|
||||||
|
if '<automatique>' in machine['macAddress'] :
|
||||||
|
return
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
# Si la machines est sur le réseau des adhérents
|
# Si la machines est sur le réseau des adhérents
|
||||||
if utils.AddrInNet(str(ip), config.NETs['wifi']):
|
if utils.AddrInNet(str(ip), config.NETs['wifi']):
|
||||||
|
@ -228,6 +228,8 @@ class firewall_wifionly(firewall):
|
||||||
def test_mac_ip_dispatch(self, func, machine):
|
def test_mac_ip_dispatch(self, func, machine):
|
||||||
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
|
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
|
||||||
ips = machine['ipHostNumber']
|
ips = machine['ipHostNumber']
|
||||||
|
if '<automatique>' in machine['macAddress'] :
|
||||||
|
return
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
# Si la machines est sur le réseau des adhérents
|
# Si la machines est sur le réseau des adhérents
|
||||||
if utils.AddrInNet(str(ip), config.NETs['wifi']):
|
if utils.AddrInNet(str(ip), config.NETs['wifi']):
|
||||||
|
|
|
@ -298,7 +298,7 @@ class firewall(base.firewall_routeur):
|
||||||
# for ip in ip_list:
|
# for ip in ip_list:
|
||||||
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
|
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
|
||||||
# # Est-ce qu'il y a des blacklists soft parmis les blacklists de la machine
|
# # 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)
|
# try: self.ipset['blacklist']['soft'].add(ip)
|
||||||
# except IpsetError: pass
|
# except IpsetError: pass
|
||||||
# else:
|
# else:
|
||||||
|
@ -310,17 +310,9 @@ class firewall(base.firewall_routeur):
|
||||||
chain = 'BLACKLIST_SOFT'
|
chain = 'BLACKLIST_SOFT'
|
||||||
|
|
||||||
if fill_ipset:
|
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
|
# On récupère la liste de toutes les ips blacklistés soft
|
||||||
bl_soft_ips = set(
|
bl_soft_ips = self.blacklisted_ips(base.config.blacklist_sanctions_soft, base.config.NETs['all'])
|
||||||
str(ip) for ips in
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
|
||||||
[
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
|
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
|
||||||
print OK
|
print OK
|
||||||
|
|
||||||
|
@ -348,7 +340,7 @@ class firewall(base.firewall_routeur):
|
||||||
# for ip in ip_list:
|
# for ip in ip_list:
|
||||||
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
|
# machine = self.conn.search(u"ipHostNumber=%s" % ip)
|
||||||
# # Est-ce qu'il y a des blacklists pour upload parmis les blacklists de la machine
|
# # 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)
|
# try: self.ipset['blacklist']['upload'].add(ip)
|
||||||
# except IpsetError: pass
|
# except IpsetError: pass
|
||||||
# else:
|
# else:
|
||||||
|
@ -360,17 +352,9 @@ class firewall(base.firewall_routeur):
|
||||||
chain = 'BLACKLIST_UPLOAD'
|
chain = 'BLACKLIST_UPLOAD'
|
||||||
|
|
||||||
if fill_ipset:
|
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
|
# On récupère la liste de toutes les ips blacklistés pour upload
|
||||||
bl_upload_ips = set(
|
bl_upload_ips = self.blacklisted_ips(base.config.blacklist_bridage_upload, base.config.NETs['all'])
|
||||||
str(ip) for ips in
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['upload'])
|
||||||
[
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
self.ipset['blacklist']['upload'].restore(bl_upload_ips)
|
self.ipset['blacklist']['upload'].restore(bl_upload_ips)
|
||||||
print OK
|
print OK
|
||||||
|
|
||||||
|
@ -446,13 +430,13 @@ class firewall(base.firewall_routeur):
|
||||||
|
|
||||||
for machine in self.machines():
|
for machine in self.machines():
|
||||||
for ip in machine['ipHostNumber']:
|
for ip in machine['ipHostNumber']:
|
||||||
if 'portTCPout' in machine.attrs.keys():
|
if 'portTCPout' in machine:
|
||||||
add_ports(ip, machine, 'tcp', 'out')
|
add_ports(ip, machine, 'tcp', 'out')
|
||||||
if 'portUDPout' in machine.attrs.keys():
|
if 'portUDPout' in machine:
|
||||||
add_ports(ip, machine, 'udp', 'out')
|
add_ports(ip, machine, 'udp', 'out')
|
||||||
if 'portTCPin' in machine.attrs.keys():
|
if 'portTCPin' in machine:
|
||||||
add_ports(ip, machine, 'tcp', 'in')
|
add_ports(ip, machine, 'tcp', 'in')
|
||||||
if 'portUDPin' in machine.attrs.keys():
|
if 'portUDPin' in machine:
|
||||||
add_ports(ip, machine, 'udp', 'in')
|
add_ports(ip, machine, 'udp', 'in')
|
||||||
|
|
||||||
self.add(table, chain, '-j REJECT')
|
self.add(table, chain, '-j REJECT')
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import netaddr
|
||||||
|
|
||||||
if '/usr/scripts/' not in sys.path:
|
if '/usr/scripts/' not in sys.path:
|
||||||
sys.path.append('/usr/scripts/')
|
sys.path.append('/usr/scripts/')
|
||||||
|
@ -58,11 +59,21 @@ class firewall_tools(object) :
|
||||||
"""Renvois la liste de toutes les machines"""
|
"""Renvois la liste de toutes les machines"""
|
||||||
if self._machines:
|
if self._machines:
|
||||||
return 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
|
||||||
|
anim('\tChargement des machines')
|
||||||
self._machines, self._adherents = self.conn.allMachinesAdherents()
|
self._machines, self._adherents = self.conn.allMachinesAdherents()
|
||||||
|
self._adherents = [ adh for adh in self._adherents if adh.paiement_ok() ]
|
||||||
|
print OK
|
||||||
return self._machines
|
return self._machines
|
||||||
|
|
||||||
def adherents(self):
|
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:
|
if self._adherents:
|
||||||
return self._adherents
|
return self._adherents
|
||||||
self._machines, self._adherents = self.conn.allMachinesAdherents()
|
self._machines, self._adherents = self.conn.allMachinesAdherents()
|
||||||
|
@ -76,8 +87,22 @@ class firewall_tools(object) :
|
||||||
self._blacklisted_machines = [ machine for machine in self.machines() if machine.blacklist_actif() ]
|
self._blacklisted_machines = [ machine for machine in self.machines() if machine.blacklist_actif() ]
|
||||||
return self._blacklisted_machines
|
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=[]):
|
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):
|
if self._blacklisted_adherents and self._blacklisted_adherents_type == set(excepts):
|
||||||
return self._blacklisted_adherents
|
return self._blacklisted_adherents
|
||||||
self._blacklisted_adherents = filter(lambda adh: adh.blacklist_actif(excepts), self.adherents())
|
self._blacklisted_adherents = filter(lambda adh: adh.blacklist_actif(excepts), self.adherents())
|
||||||
|
@ -218,10 +243,7 @@ class firewall_tools(object) :
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Démarre le pare-feu : génère les règles, puis les restore"""
|
"""Démarre le pare-feu : génère les règles, puis les restore"""
|
||||||
anim('\tChargement des machines')
|
|
||||||
self.machines()
|
self.machines()
|
||||||
self.blacklisted_machines()
|
|
||||||
print OK
|
|
||||||
|
|
||||||
if squeeze:
|
if squeeze:
|
||||||
anim('\tVidage du pare-feu')
|
anim('\tVidage du pare-feu')
|
||||||
|
|
|
@ -102,8 +102,8 @@ class firewall(base.firewall):
|
||||||
self.add(table, chain, '-d 127.0.0.1/8 -j RETURN')
|
self.add(table, chain, '-d 127.0.0.1/8 -j RETURN')
|
||||||
for net in base.config.NETs['all']:
|
for net in base.config.NETs['all']:
|
||||||
self.add(table, chain, '-d %s -j RETURN' % net)
|
self.add(table, chain, '-d %s -j RETURN' % net)
|
||||||
for adh in self.blacklisted_adherents(['paiement']):
|
for adh in self.blacklisted_adherents():
|
||||||
if 'uidNumber' in adh.attrs.keys():
|
if 'uidNumber' in adh:
|
||||||
self.add(table, chain, '-m owner --uid-owner %s -j REJECT' % adh['uidNumber'][0])
|
self.add(table, chain, '-m owner --uid-owner %s -j REJECT' % adh['uidNumber'][0])
|
||||||
print OK
|
print OK
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ arguments peuvent être founis pour une même option, les séparer par &
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys, signal, os, getopt
|
import sys, signal, os, getopt
|
||||||
|
from trigger import trigger_generate as trigger
|
||||||
sys.path.append('/usr/scripts/gestion')
|
sys.path.append('/usr/scripts/gestion')
|
||||||
|
|
||||||
from ldap_crans import crans_ldap, hostname
|
from ldap_crans import crans_ldap, hostname
|
||||||
|
@ -28,8 +28,6 @@ from syslog import *
|
||||||
import platform
|
import platform
|
||||||
openlog("generate")
|
openlog("generate")
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
|
|
||||||
|
|
||||||
db = crans_ldap()
|
db = crans_ldap()
|
||||||
make_lock('auto_generate', 'Big lock', nowait=1)
|
make_lock('auto_generate', 'Big lock', nowait=1)
|
||||||
|
|
||||||
|
@ -205,15 +203,6 @@ class owl(base_reconfigure):
|
||||||
from adherents import del_user
|
from adherents import del_user
|
||||||
self._do(del_user(args))
|
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):
|
class thot(base_reconfigure):
|
||||||
def surveillance_exemptions(self):
|
def surveillance_exemptions(self):
|
||||||
from gen_confs.surveillance import exemptions
|
from gen_confs.surveillance import exemptions
|
||||||
|
@ -304,10 +293,10 @@ class gordon(base_reconfigure) :
|
||||||
class titanic(base_reconfigure):
|
class titanic(base_reconfigure):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL) # Comportement normal de Ctrl-C
|
|
||||||
remove_lock('auto_generate')
|
remove_lock('auto_generate')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_IGN) # Pas de Ctrl-C
|
||||||
openlog('generate', LOG_PID)
|
openlog('generate', LOG_PID)
|
||||||
for x in db.services_to_restart():
|
for x in db.services_to_restart():
|
||||||
try:
|
try:
|
||||||
|
@ -362,15 +351,17 @@ if __name__ == '__main__':
|
||||||
print 'Recherche des personnes en fin de sanction...'
|
print 'Recherche des personnes en fin de sanction...'
|
||||||
c = db.search('blacklist=*')
|
c = db.search('blacklist=*')
|
||||||
services = []
|
services = []
|
||||||
|
nom = time()
|
||||||
hier = time() - 24*3600
|
hier = time() - 24*3600
|
||||||
|
demain = time() + 24*3600
|
||||||
for a_reco in c['adherent'] + c['machine'] + c['club']:
|
for a_reco in c['adherent'] + c['machine'] + c['club']:
|
||||||
for bl in a_reco.blacklist():
|
for bl in a_reco.blacklist():
|
||||||
fin, sanction = bl.split('$')[1:3]
|
fin, sanction = bl.split('$')[1:3]
|
||||||
if fin > hier and sanction not in services:
|
if fin != '-' and fin <= demain and fin >= now and (sanction, fin) not in services:
|
||||||
services.append(sanction)
|
services.append((sanction, fin))
|
||||||
for s in services:
|
for s,f in services:
|
||||||
print "Ajout de blacklist_%s pour reconfiguration" % s
|
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)
|
sys.exit(0)
|
||||||
|
|
||||||
elif opt == '--add':
|
elif opt == '--add':
|
||||||
|
@ -397,3 +388,4 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
# On fait ce qu'il y a à faire
|
# On fait ce qu'il y a à faire
|
||||||
classe(to_do)
|
classe(to_do)
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL) # Comportement normal de Ctrl-C
|
||||||
|
|
|
@ -19,11 +19,8 @@ import sys
|
||||||
sys.path.append('/usr/scripts/gestion')
|
sys.path.append('/usr/scripts/gestion')
|
||||||
|
|
||||||
import commands
|
import commands
|
||||||
import lock
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class IpsetError(Exception):
|
class IpsetError(Exception):
|
||||||
# Gestion des erreurs d'ipset
|
# Gestion des erreurs d'ipset
|
||||||
def __init__(self,cmd,err_code,output):
|
def __init__(self,cmd,err_code,output):
|
||||||
|
|
|
@ -57,10 +57,11 @@ def ssh_keygen(algo,size):
|
||||||
print("Nouvelle clef %s générée" % key_path)
|
print("Nouvelle clef %s générée" % key_path)
|
||||||
|
|
||||||
def get_machines():
|
def get_machines():
|
||||||
machines=[]
|
filter=""
|
||||||
for ip in set(ip4_addresses()):
|
for ip in set(ip4_addresses()):
|
||||||
machines.extend(conn.search(u'ipHostNumber=%s' % ip, mode='rw'))
|
filter+=u'(ipHostNumber=%s)' % ip
|
||||||
return machines
|
filter = u"(|%s)" % filter
|
||||||
|
return conn.search(filter, mode='rw')
|
||||||
|
|
||||||
def check_keys_age(key_path,algo):
|
def check_keys_age(key_path,algo):
|
||||||
age=time.time()-os.path.getmtime(key_path)
|
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
|
key_path='/etc/ssh/ssh_host_%s_key.pub' % algo
|
||||||
if os.path.isfile(key_path):
|
if os.path.isfile(key_path):
|
||||||
check_keys_age(key_path,algo)
|
check_keys_age(key_path,algo)
|
||||||
keys[algo]=open(key_path).read()
|
keys[algo]=unicode(open(key_path).read().strip())
|
||||||
return keys
|
return keys
|
||||||
|
|
||||||
def check_keys(keys):
|
def check_keys(keys):
|
||||||
return dict([ (algo,key.split()[1] == ssh_keyscan('localhost',algo)) for algo,key in keys.items() ])
|
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()
|
keys=get_local_keys()
|
||||||
validation=check_keys(keys)
|
validation=check_keys(keys)
|
||||||
machines=get_machines()
|
return [key for algo,key in keys.items() if validation[algo]]
|
||||||
for machine in machines:
|
|
||||||
sshkeys_old=[key.value for key in machine.get('sshFingerprint',[])]
|
def publish_keys():
|
||||||
sshkeys_new=[key.decode('UTF-8') for algo,key in keys.items() if validation[algo]]
|
keys=valid_keys()
|
||||||
if not set(sshkeys_old)==set(sshkeys_new):
|
for machine in get_machines():
|
||||||
machine['sshFingerprint']=sshkeys_new
|
with machine:
|
||||||
machine.save()
|
if machine['sshFingerprint'] != keys:
|
||||||
|
print "Key list changed"
|
||||||
|
machine['sshFingerprint'] = keys
|
||||||
|
machine.save()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__' :
|
if __name__ == '__main__' :
|
||||||
|
|
|
@ -49,6 +49,9 @@ class exemptions(gen_config) :
|
||||||
source = machine.ip()
|
source = machine.ip()
|
||||||
else:
|
else:
|
||||||
source = machine.ipv6()
|
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)
|
requete="INSERT INTO exemptes (ip_crans,ip_dest) VALUES ('%s','%s')" % (source, destination)
|
||||||
curseur.execute(requete)
|
curseur.execute(requete)
|
||||||
|
|
||||||
|
@ -83,6 +86,10 @@ class machines(gen_config) :
|
||||||
|
|
||||||
ipv6_vu={}
|
ipv6_vu={}
|
||||||
def ipv6_already_set(ipv6):
|
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)
|
ret = ipv6_vu.get(ipv6, False)
|
||||||
ipv6_vu[ipv6] = True
|
ipv6_vu[ipv6] = True
|
||||||
return ret
|
return ret
|
||||||
|
|
37
gestion/gen_confs/trigger.py
Executable file
37
gestion/gen_confs/trigger.py
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
_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'
|
||||||
|
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:
|
||||||
|
p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
out, err = p.communicate()
|
||||||
|
if err:
|
||||||
|
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 &')
|
|
@ -933,7 +933,7 @@ def __prompt_input_menu(method, titre, prompt):
|
||||||
else:
|
else:
|
||||||
method([num-1, val])
|
method([num-1, val])
|
||||||
|
|
||||||
except ValueError, c:
|
except (EnvironmentError, ValueError) as c:
|
||||||
arg = u'--title "%s" ' % titre
|
arg = u'--title "%s" ' % titre
|
||||||
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(c.args[0])
|
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(c.args[0])
|
||||||
dialog(arg)
|
dialog(arg)
|
||||||
|
@ -1135,7 +1135,7 @@ def confirm(clas):
|
||||||
return 1
|
return 1
|
||||||
try:
|
try:
|
||||||
res = clas.save()
|
res = clas.save()
|
||||||
except RuntimeError, c:
|
except (EnvironmentError, RuntimeError) as c:
|
||||||
arg = u'--title "Enregistrement" '
|
arg = u'--title "Enregistrement" '
|
||||||
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(c.args[0])
|
arg += u'--msgbox "%s\n\n\n" 0 0' % to_unicode(c.args[0])
|
||||||
dialog(arg)
|
dialog(arg)
|
||||||
|
|
305
gestion/gest_crans_lc.py
Executable file
305
gestion/gest_crans_lc.py
Executable file
|
@ -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')
|
|
@ -24,7 +24,11 @@ import netaddr
|
||||||
|
|
||||||
def mac_to_ipv6(ipv6_prefix, mac_address):
|
def mac_to_ipv6(ipv6_prefix, mac_address):
|
||||||
"""Convert a MAC address (EUI48) to an IPv6 (prefix::EUI64)."""
|
"""Convert a MAC address (EUI48) to an IPv6 (prefix::EUI64)."""
|
||||||
|
if mac_address == '<automatique>':
|
||||||
|
return ''
|
||||||
|
|
||||||
|
if type(mac_address) in [str, unicode]:
|
||||||
|
mac_address = netaddr.EUI(mac_address)
|
||||||
addr = int(mac_address.bits(netaddr.mac_bare), 2)
|
addr = int(mac_address.bits(netaddr.mac_bare), 2)
|
||||||
ip6addr = (((addr >> 24) ^ (1 << 17)) << 40) | (0xFFFE << 24) | (addr & 0xFFFFFF)
|
ip6addr = (((addr >> 24) ^ (1 << 17)) << 40) | (0xFFFE << 24) | (addr & 0xFFFFFF)
|
||||||
n = netaddr.IPNetwork(ipv6_prefix)
|
n = netaddr.IPNetwork(ipv6_prefix)
|
||||||
|
|
|
@ -30,6 +30,7 @@ from iptools import AddrInNet
|
||||||
from ridtools import Rid, find_rid_plage
|
from ridtools import Rid, find_rid_plage
|
||||||
import subprocess
|
import subprocess
|
||||||
import netaddr
|
import netaddr
|
||||||
|
import ip6tools
|
||||||
|
|
||||||
blacklist_sanctions_ipv6 = list(blacklist_sanctions)
|
blacklist_sanctions_ipv6 = list(blacklist_sanctions)
|
||||||
blacklist_sanctions_ipv6.extend(blacklist_sanctions_soft)
|
blacklist_sanctions_ipv6.extend(blacklist_sanctions_soft)
|
||||||
|
@ -126,6 +127,8 @@ class Ip6tables(object):
|
||||||
|
|
||||||
def macip(self, mac, type_m):
|
def macip(self, mac, type_m):
|
||||||
'''Fait la correspondance MAC-IP'''
|
'''Fait la correspondance MAC-IP'''
|
||||||
|
if '<automatique>' == mac:
|
||||||
|
return
|
||||||
tab = {'serveurs' : 'fil' }
|
tab = {'serveurs' : 'fil' }
|
||||||
if type_m in tab.keys(): type_m = tab[type_m]
|
if type_m in tab.keys(): type_m = tab[type_m]
|
||||||
type_mm = re.sub('-', '', type_m)
|
type_mm = re.sub('-', '', type_m)
|
||||||
|
@ -141,6 +144,8 @@ class Ip6tables(object):
|
||||||
'wifi-adh-v6' : 'extwifiv6',
|
'wifi-adh-v6' : 'extwifiv6',
|
||||||
'serveurs':'extfil' }
|
'serveurs':'extfil' }
|
||||||
ip = ipv6_addr(mac, type_machine)
|
ip = ipv6_addr(mac, type_machine)
|
||||||
|
if not ip:
|
||||||
|
return
|
||||||
for proto in ['tcp', 'udp']:
|
for proto in ['tcp', 'udp']:
|
||||||
for port in ports[proto]:
|
for port in ports[proto]:
|
||||||
if port != ':':
|
if port != ':':
|
||||||
|
@ -157,6 +162,8 @@ ACCEPT' % (dev, proto, ip, port))
|
||||||
'wifi-adh-v6' : 'cranswifiv6',
|
'wifi-adh-v6' : 'cranswifiv6',
|
||||||
'serveurs':'cransfil' }
|
'serveurs':'cransfil' }
|
||||||
ip = ipv6_addr(mac, type_machine)
|
ip = ipv6_addr(mac, type_machine)
|
||||||
|
if not ip:
|
||||||
|
return
|
||||||
for proto in ['tcp', 'udp']:
|
for proto in ['tcp', 'udp']:
|
||||||
for port in ports[proto]:
|
for port in ports[proto]:
|
||||||
if port != ':':
|
if port != ':':
|
||||||
|
@ -470,9 +477,7 @@ def check_ip_proto(ip_proto):
|
||||||
|
|
||||||
def ipv6_addr(mac, net):
|
def ipv6_addr(mac, net):
|
||||||
''' Renvoie l'adresse ipv6 d'auto-configuration de la mac sur le réseau '''
|
''' Renvoie l'adresse ipv6 d'auto-configuration de la mac sur le réseau '''
|
||||||
mac_s = mac.split(':')
|
return ip6tools.mac_to_ipv6(prefix[dprefix[net]][0], mac)
|
||||||
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])
|
|
||||||
|
|
||||||
def mac_addr(ipv6):
|
def mac_addr(ipv6):
|
||||||
''' Renvoie l'adresse mac de l'ipv6 d'auto-configuration '''
|
''' Renvoie l'adresse mac de l'ipv6 d'auto-configuration '''
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
# baie_lib.py
|
# baie_lib.py
|
||||||
# ----------
|
# ----------
|
||||||
# Type à taper si ça chie : Pierre-Elliott Bécue <peb@crans.org>
|
# Type à taper si ça chie : Pierre-Elliott Bécue <peb@crans.org>
|
||||||
# Licence : WTFPL
|
# Licence : WTFPL
|
||||||
|
|
||||||
'''Bibliothèque pour accéder à la baie de stockage nols, récupère les données
|
'''Bibliothèque pour accéder à la baie de stockage nols, récupère les données
|
||||||
|
@ -113,7 +113,7 @@ class Nols(object):
|
||||||
Objects = tree.findall("OBJECT")
|
Objects = tree.findall("OBJECT")
|
||||||
#Objects = tree.findall("OBJECT[@name='volume-view']")
|
#Objects = tree.findall("OBJECT[@name='volume-view']")
|
||||||
## Fin cf juste en dessous
|
## Fin cf juste en dessous
|
||||||
|
|
||||||
for Object in Objects:
|
for Object in Objects:
|
||||||
name = None
|
name = None
|
||||||
lun = None
|
lun = None
|
||||||
|
@ -121,7 +121,7 @@ class Nols(object):
|
||||||
# la merde que j'ai fait juste après.
|
# la merde que j'ai fait juste après.
|
||||||
#name = Object.findall("PROPERTY[@name='volume-name']")[0].text
|
#name = Object.findall("PROPERTY[@name='volume-name']")[0].text
|
||||||
#lun = Object.findall("OBJECT/PROPERTY[@name='lun']")[0].text
|
#lun = Object.findall("OBJECT/PROPERTY[@name='lun']")[0].text
|
||||||
|
|
||||||
######## Début merde que j'ai faite juste après ###########
|
######## Début merde que j'ai faite juste après ###########
|
||||||
if not (Object.attrib['name'] == "volume-view"):
|
if not (Object.attrib['name'] == "volume-view"):
|
||||||
pass
|
pass
|
||||||
|
@ -178,5 +178,5 @@ class Nols(object):
|
||||||
|
|
||||||
def rename_volume(self, origin_name, new_name):
|
def rename_volume(self, origin_name, new_name):
|
||||||
'''Renomme un volume.'''
|
'''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))
|
||||||
|
|
|
@ -223,6 +223,9 @@ def format_mac(mac):
|
||||||
Le séparateur original peut être :, - ou rien
|
Le séparateur original peut être :, - ou rien
|
||||||
Retourne la mac formatée.
|
Retourne la mac formatée.
|
||||||
"""
|
"""
|
||||||
|
mac = mac.strip()
|
||||||
|
if mac == '<automatique>':
|
||||||
|
return mac
|
||||||
l, mac = preattr(mac)
|
l, mac = preattr(mac)
|
||||||
mac = mac.strip().replace(' ','').replace("-", ":")
|
mac = mac.strip().replace(' ','').replace("-", ":")
|
||||||
if mac.count(":") == 5:
|
if mac.count(":") == 5:
|
||||||
|
@ -2863,6 +2866,10 @@ class Machine(BaseClasseCrans):
|
||||||
|
|
||||||
mac = format_mac(mac)
|
mac = format_mac(mac)
|
||||||
|
|
||||||
|
if mac == '<automatique>':
|
||||||
|
multi_ok = True
|
||||||
|
lock = False
|
||||||
|
|
||||||
# La MAC serait-elle une MAC à la con ?
|
# La MAC serait-elle une MAC à la con ?
|
||||||
if mac == "00:04:4b:80:80:03":
|
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)
|
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:
|
try:
|
||||||
self._set('macAddress', [mac])
|
self._set('macAddress', [mac])
|
||||||
if net.size > 1:
|
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:
|
else:
|
||||||
self.ipv6(config.ipv6_machines_speciales[int(self.rid())], lock)
|
self.ipv6(config.ipv6_machines_speciales[int(self.rid())], lock)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -3001,6 +3008,9 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
|
||||||
|
|
||||||
if type(new) == list:
|
if type(new) == list:
|
||||||
# Modif
|
# 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]
|
index = new[0]
|
||||||
new = new[1]
|
new = new[1]
|
||||||
if new == '':
|
if new == '':
|
||||||
|
@ -3214,6 +3224,12 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
|
||||||
|
|
||||||
ret = ''
|
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 ?
|
# Besoin de redémarrer les firewalls ?
|
||||||
if 'ipHostNumber' in self.modifs or 'macAddress' in self.modifs:
|
if 'ipHostNumber' in self.modifs or 'macAddress' in self.modifs:
|
||||||
reconf_ip = self._init_data.get('ipHostNumber', [])
|
reconf_ip = self._init_data.get('ipHostNumber', [])
|
||||||
|
@ -3294,6 +3310,9 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
|
||||||
if self.proprietaire().__class__ == AssociationCrans and not isadm():
|
if self.proprietaire().__class__ == AssociationCrans and not isadm():
|
||||||
raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.')
|
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.proprio = self.__proprietaire.Nom() # On met dans un coin le nom du proprio
|
||||||
self.__proprietaire = None # On oublie le propriétaire
|
self.__proprietaire = None # On oublie le propriétaire
|
||||||
|
@ -3390,7 +3409,14 @@ Contactez nounou si la MAC est bien celle d'une carte.""", 3)
|
||||||
"""Retourne l'adresse IPv6 correspondant à la machine"""
|
"""Retourne l'adresse IPv6 correspondant à la machine"""
|
||||||
|
|
||||||
if ipv6 == None:
|
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)
|
ipv6 = str(ipv6)
|
||||||
net = self.netv6()
|
net = self.netv6()
|
||||||
|
|
52
gestion/mail/convocation_ago.py
Executable file
52
gestion/mail/convocation_ago.py
Executable file
|
@ -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
|
|
@ -32,7 +32,7 @@ markup = {
|
||||||
|
|
||||||
### For an example:
|
### For an example:
|
||||||
### print generate('bienvenue', {'From':'respbats@crans.org', 'To':'admin@genua.fr', 'lang_info':'English version below'}).as_string()
|
### 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'):
|
def submessage(playload, type, charset='utf-8'):
|
||||||
"""Renvois un sous message à mettre dans un message multipart"""
|
"""Renvois un sous message à mettre dans un message multipart"""
|
||||||
|
|
1
gestion/mail/template/ago/From/fr
Normal file
1
gestion/mail/template/ago/From/fr
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Le CA du Crans <{{From}}>
|
1
gestion/mail/template/ago/Subject/fr
Normal file
1
gestion/mail/template/ago/Subject/fr
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[Crans] Convocation à l'Assemblée Générale Ordinaire de l'association
|
1
gestion/mail/template/ago/To/fr
Normal file
1
gestion/mail/template/ago/To/fr
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{{To}}
|
37
gestion/mail/template/ago/body/en
Normal file
37
gestion/mail/template/ago/body/en
Normal file
|
@ -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
|
45
gestion/mail/template/ago/body/fr
Normal file
45
gestion/mail/template/ago/body/fr
Normal file
|
@ -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
|
||||||
|
|
|
@ -11,6 +11,10 @@ Attention, ce fichier est osbolète
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import cPickle, sys
|
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
|
import config
|
||||||
from whos import aff
|
from whos import aff
|
||||||
|
|
|
@ -31,7 +31,7 @@ import getpass
|
||||||
def get(secret):
|
def get(secret):
|
||||||
""" Recupere un secret. """
|
""" Recupere un secret. """
|
||||||
openlog('secrets_new')
|
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))
|
syslog('%s (in %s) asked for %s' % (getpass.getuser(), prog, secret))
|
||||||
try:
|
try:
|
||||||
f = open("/etc/crans/secrets/" + secret)
|
f = open("/etc/crans/secrets/" + secret)
|
||||||
|
|
|
@ -11,6 +11,9 @@ import services
|
||||||
if not 'crans-nfs' in services.services or not socket.gethostname() in services.services['crans-nfs']:
|
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")
|
sys.stderr.write("Devrait être exécuté sur une machine du groupe 'crans-nfs'\n")
|
||||||
exit(1)
|
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 lc_ldap.shortcuts
|
||||||
import gestion.gen_confs.adherents
|
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']:
|
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]))
|
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:
|
if l:
|
||||||
h=gestion.gen_confs.adherents.home(l)
|
h=gestion.gen_confs.adherents.home(l)
|
||||||
h.reconfigure()
|
h.reconfigure()
|
||||||
|
|
||||||
|
|
8
gestion/virtualisation/gen_net_udev.sh
Executable file
8
gestion/virtualisation/gen_net_udev.sh
Executable file
|
@ -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'
|
||||||
|
|
46
gestion/virtualisation/vmid
Executable file
46
gestion/virtualisation/vmid
Executable file
|
@ -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
|
|
@ -670,7 +670,8 @@ def machine_details(machine) :
|
||||||
|
|
||||||
f+= coul(u'IP : ','gras') + "%s\t\t" %machine.ip()
|
f+= coul(u'IP : ','gras') + "%s\t\t" %machine.ip()
|
||||||
f+= coul(u'MAC : ','gras') + "%s\n" %machine.mac()
|
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:
|
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"
|
f += u"\n".join([coul(u'Fingerprint SSH : ', 'gras') + u"%s" % (i) for i in machine.sshFingerprint()])+"\n"
|
||||||
|
|
|
@ -9,7 +9,7 @@ import lc_ldap.filter2 as filter
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) >1:
|
if len(sys.argv) >1:
|
||||||
conn=lc_ldap.shortcuts.lc_ldap_admin()
|
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:
|
if not result:
|
||||||
print "rien trouvé"
|
print "rien trouvé"
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -33,9 +33,10 @@ import commands
|
||||||
import string
|
import string
|
||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
sys.path.append("/usr/scripts/")
|
if not '/usr/scripts' in sys.path:
|
||||||
|
sys.path.append("/usr/scripts")
|
||||||
import cranslib.utils.files
|
import cranslib.utils.files
|
||||||
import secrets_new
|
import gestion.secrets_new as secrets_new
|
||||||
|
|
||||||
digicode_pass = secrets_new.get("digicode_pass")
|
digicode_pass = secrets_new.get("digicode_pass")
|
||||||
# #############################################################
|
# #############################################################
|
||||||
|
|
|
@ -22,6 +22,9 @@ import tempfile
|
||||||
|
|
||||||
from hosts_plugins import hosts_plugins, general_plugins
|
from hosts_plugins import hosts_plugins, general_plugins
|
||||||
|
|
||||||
|
from gestion.config.services import services
|
||||||
|
|
||||||
|
|
||||||
# Plugins munin classiques à ignorer
|
# Plugins munin classiques à ignorer
|
||||||
IGNORE_PLUGINS = (
|
IGNORE_PLUGINS = (
|
||||||
'apt_all',
|
'apt_all',
|
||||||
|
@ -39,6 +42,13 @@ IGNORE_PLUGINS = (
|
||||||
'vlan_',
|
'vlan_',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if socket.gethostname() in services.services.get('iscsi', []):
|
||||||
|
IGNORE_PLUGINS += (
|
||||||
|
'diskstat',
|
||||||
|
'diskstats',
|
||||||
|
'diskstat_',
|
||||||
|
)
|
||||||
|
|
||||||
# Chemin d'accès aux plugins munin
|
# Chemin d'accès aux plugins munin
|
||||||
MUNIN_PATH = "/usr/share/munin/plugins"
|
MUNIN_PATH = "/usr/share/munin/plugins"
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ def dir(path):
|
||||||
return l
|
return l
|
||||||
multicast={
|
multicast={
|
||||||
'Radio': {
|
'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']),
|
'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 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']),
|
'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']),
|
# '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/']),
|
'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']),
|
'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']),
|
'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']),
|
'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']),
|
'France Culture': ('culture', '239.231.140.175', '1234', ['http://95.81.147.3/franceculture/all/franceculturehautdebit.mp3']),
|
||||||
|
|
|
@ -51,6 +51,12 @@ def do_auth(mac, prise):
|
||||||
conn = crans_ldap(readonly=True)
|
conn = crans_ldap(readonly=True)
|
||||||
m = conn.search('mac=%s' % mac)['machine']
|
m = conn.search('mac=%s' % mac)['machine']
|
||||||
if len(m) == 0:
|
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")
|
return (0, "Mac inconnue", "accueil")
|
||||||
elif len(m) > 1:
|
elif len(m) > 1:
|
||||||
return (-1, "Pb recherche mac (nb résultat %d!=1)" % len(m), "")
|
return (-1, "Pb recherche mac (nb résultat %d!=1)" % len(m), "")
|
||||||
|
|
61
wiki/macro/AllPagesWithACL.py
Normal file
61
wiki/macro/AllPagesWithACL.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# -*- 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
|
||||||
|
|
||||||
|
Modifié par Vincent Le Galli <legallic@crans.org>
|
||||||
|
(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
|
||||||
|
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 = "<p><b>All pages:</b><br>"
|
||||||
|
all = {}
|
||||||
|
pages = macro.request.rootpage.getPageList()
|
||||||
|
# pages = macro.request.rootpage.getPageList(filter = re.compile("^WikiSandBox").match)
|
||||||
|
html += "Total: %s pages </p>" % str(len(pages))
|
||||||
|
|
||||||
|
for pagename in pages:
|
||||||
|
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 += "<table>"
|
||||||
|
all1 = sorted(all.items())
|
||||||
|
for pg, ac in all1:
|
||||||
|
if ac != "not defined":
|
||||||
|
html += "<tr><td>%s</td>" % pg
|
||||||
|
html += "<td>%s</td></tr>" % ac
|
||||||
|
html += "</table>"
|
||||||
|
|
||||||
|
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(
|
||||||
|
"<<AllPagesWithACL: %s>>" % err.args[0])
|
||||||
|
|
|
@ -101,6 +101,49 @@ class Theme(ThemeBase):
|
||||||
'{o}': ("{o}", "star_off.png", 16, 16),
|
'{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'<li class="%s">%s</li>'
|
||||||
|
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'''
|
||||||
|
<ul id="navibar">
|
||||||
|
%s
|
||||||
|
</ul>
|
||||||
|
''' % items
|
||||||
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def wikipanel(self, d):
|
def wikipanel(self, d):
|
||||||
""" Create wiki panel """
|
""" Create wiki panel """
|
||||||
_ = self.request.getText
|
_ = self.request.getText
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue