scripts/radius_auth.py
Olivier Huber f84db66b7e [./radius_auth.py] Les machines en blackliste virus et ipv6_ra sont sur le vlan isolement
darcs-hash:20091017130953-8fbb1-2af13a6472ad2f5fa3f1b02dffa2bab1e74374c8.gz
2009-10-17 15:09:53 +02:00

105 lines
3.8 KiB
Python

#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
import os, md5, 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
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 md5.new(password[0] + clear_pass + challenge).digest() == password[1:] :
return True
except :
return False
def do_auth(mac):
"""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
if not chap_ok(os.getenv('CHAP_PASSWORD'), os.getenv('CHAP_CHALLENGE'), mac):
return (-1, "Échec test CHAP", "")
# Mac dans la base LDAP
m = crans_ldap(readonly=True).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() :
return (0, "Bad boy", "isolement")
# L'adherent ne paie pas, on le met sur le vlan radin
if ((not isinstance(proprio, Club) and not proprio.adherentPayant()) or \
('Nounou' in proprio.droits() and AddrInNet(m[0].ip(),'10.42.0.0/16'))):
return (0, "Ne paie pas", "gratuit")
# Paiment ok ?
paid = max(proprio.paiement() + [0])
if dat[1] in (8, 9):
# En septembre les anciennes adhésions sont OK
ann_scol -= 1
elif dat[1] == 10 and dat[2] in (1,2,3):
# On laisse 3 jours ou les gens ont une page sur squid
ann_scol -= 1
if ann_scol > paid:
return (0, "N'a pas payé", "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__' :
# Test chap (comme cela on est sur que c'est bien un switch qui demande)
mac = os.getenv('USER_NAME', '').replace('"', '')
# On vérifie si la mac est autorisée
(r, msg, vlan) = do_auth(mac)
# On logue la prise sur laquelle a lieu la tentative
openlog("radius_auth.py")
switch = os.getenv("NAS_IDENTIFIER", "").replace('"', '')
prise = (len(switch) == 6 and (switch[3] + switch[5]) or (switch + "-"))
prise += "%02d" % int(os.getenv("NAS_PORT", 0))
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]])
sys.exit(r)