scripts/radius_auth.py
Daniel STAN 9551545593 [radius_auth] Auth possible uniquement depuis une chbre d'adhérent
Ignore-this: 1977068e83e9be1619fb8b946433c61d
Sauf pour les membres actifs (tests de maintenance, toussa)

Au passage, il faudrait rajouter aussi une limitation au niveau
des machines clubs, qui ne devraient pouvoir être connectées que
sur la prise dudit club.

darcs-hash:20121109012845-28565-25619e6a508450c2f9fbb00c2a0ae81e63ece194.gz
2012-11-09 02:28:45 +01:00

128 lines
4.4 KiB
Python

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os, hashlib, sys, binascii
from syslog import syslog, openlog
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, AssociationCrans, Club
from config import ann_scol, dat, vlans, periode_transitoire
import annuaires_pg
from iptools import AddrInNet
def chap_ok(password, challenge, clear_pass) :
""" Test l'authentification chap fournie
password et chalenge doivent être données
en hexa (avec ou sans le 0x devant)
retourne True si l'authentification est OK
retourne False sinon
"""
try :
challenge = binascii.a2b_hex(challenge.replace('0x',''))
password = binascii.a2b_hex(password.replace('0x',''))
if hashlib.md5(password[0] + clear_pass + challenge).digest() == password[1:] :
return True
except :
return False
def paiement_ok(adh):
"""Paiment ok ?"""
global ann_scol
paid = max(adh.paiement() + [0])
if periode_transitoire:
# Si periode transitoire, on accepte les personnes n'ayant pas
# réadhéré
ann_scol -= 1
return ann_scol <= paid
def do_auth(mac, prise):
"""Effectue l'authentification. Renvoie (success, msg,
vlan). success est 0 si l'authentification est réussie, msg est
pour les logs et vlan est le vlan non taggé à utiliser pour la
prise."""
global ann_scol
# Test chap (comme cela on est sur que c'est bien un switch qui demande)
if not chap_ok(os.getenv('CHAP_PASSWORD'), os.getenv('CHAP_CHALLENGE'), mac):
return (-1, "Échec test CHAP", "")
# Mac dans la base LDAP
conn = crans_ldap(readonly=True)
m = conn.search('mac=%s' % mac)['machine']
if len(m) == 0:
return (0, "Mac inconnue", "accueil")
elif len(m) > 1:
return (-1, "Pb recherche mac (nb résultat %d!=1)" % len(m), "")
# N'appartient pas au Crans et n'a pas de prise attribuée
# donc sur uplink ou switch non filtré
# But : éviter le spoof d'une mac d'une machine clef
proprio = m[0].proprietaire()
if proprio.__class__ == AssociationCrans and m[0].prise() == u'N/A':
return (-1, "Machine du crans", "")
# blockliste bloq
if 'bloq' in m[0].blacklist_actif():
return (-1, "Bloquage total des services pour cette machine", "")
# les gens qui doivent être isolés
if ('virus' in m[0].blacklist_actif() or 'ipv6_ra' in m[0].blacklist_actif()
or 'autodisc_virus' in m[0].blacklist_actif()):
return (0, "Bad boy", "isolement")
# Paiement proprio ?
if not paiement_ok(proprio):
return (0, "N'a pas payé", "accueil")
# Si l'adhérent n'est pas membre actif, il doit se brancher depuis la prise
# d'un autre adhérent à jour de cotisation
if not proprio.droits():
try:
chbre = prise[0] + annuaires_pg.reverse(prise[0], prise[1:])[0]
except IndexError:
return (0, "Chambre inconnue", "accueil")
hebergeurs = conn.search('chambre=' + chbre)
for hebergeur in hebergeurs['adherent'] + hebergeurs['club']:
if paiement_ok(hebergeur):
break
else:
return (0, "Hébergeur non à jour", "accueil")
# Cas des personnels logés dans les appartements de l'ENS
if (proprio.etudes(0) == 'Personnel ENS' or
('Nounou' in proprio.droits() and AddrInNet(m[0].ip(),'10.2.9.0/24'))):
return (0, "Personnel ENS", "appts")
# C'est bon
return (0, "Accès adhérent OK", "adherent")
if __name__ == '__main__' :
mac = os.getenv('USER_NAME', '').replace('"', '')
switch = os.getenv("NAS_IDENTIFIER", "").replace('"', '').split('.')[0]
prise = (len(switch) == 6 and (switch[3] + switch[5]) or (switch + "-"))
prise += "%02d" % int(os.getenv("NAS_PORT", 0))
# On vérifie si la mac est autorisée
(r, msg, vlan) = do_auth(mac, prise)
# On logue la prise sur laquelle a lieu la tentative
openlog("radius_auth.py")
syslog("%s -> %s [%s]" % (prise, mac, msg))
if vlan:
# Cela indique au switch comment configurer le vlan par défaut
# pour cette prise
print ", ".join(["Tunnel-Type = VLAN",
"Tunnel-Medium-Type = IEEE-802",
"Tunnel-Private-Group-Id = \"%d\"" % vlans[vlan]])
# On tente de logguer la dernière mac sur une prise donnée
try:
f = open('/usr/scripts/var/last_macs/' + prise,'w')
f.write(mac)
f.close()
except:
pass
sys.exit(r)