From e0f16edf28ed7d743c6711f19aecbf4b35c75b86 Mon Sep 17 00:00:00 2001 From: Daniel STAN Date: Wed, 26 Feb 2014 00:33:54 +0100 Subject: [PATCH] radius: (wip) enregistrement mac MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quand une machine se connecte pour la première fois, et qu'elle a une mac auto on enregistre la vraie, et on trigger generate sur komaz. --- freeradius/auth.py | 85 ++++++++++++++++++++++++++++++++++++---------- freeradius/test.py | 9 +++-- 2 files changed, 75 insertions(+), 19 deletions(-) diff --git a/freeradius/auth.py b/freeradius/auth.py index f45aa9af..8ffcbd80 100644 --- a/freeradius/auth.py +++ b/freeradius/auth.py @@ -19,12 +19,14 @@ # Voir des exemples plus complets ici: # https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/ -from lc_ldap.shortcuts import with_ldap_conn, lc_ldap_anonymous +from lc_ldap.shortcuts import with_ldap_conn, lc_ldap_admin from lc_ldap.crans_utils import escape as escape_ldap +import lc_ldap.crans_utils from gestion.config.config import vlans import lc_ldap.objets import radiusd import netaddr +from gestion.gen_confs.generate import trigger as trigger_generate # Voilà, pour faire marcher le V6Only, il faut se retirer l'ipv4 de sa machine # ou en enregistrer une nouvelle (sans ipv4) avec une autre mac. Moi j'ai la @@ -41,6 +43,10 @@ bl_isolement = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra'] # TODO LOGSSSSS bl_accueil = [u'carte_etudiant', u'chambre_invalide', u'paiement'] +# Decorateur utilisé plus tard (same connection) +use_ldap = with_ldap_conn(retries=2, delay=5, constructor=lc_ldap_admin) + +@use_ldap def get_machines(auth_data, conn): mac = None username = None @@ -49,18 +55,40 @@ def get_machines(auth_data, conn): # Calling-Station-Id: "une_adresse_mac" for (key, value) in auth_data: if key == 'Calling-Station-Id': - mac = escape_ldap(value.decode('ascii', 'ignore').replace('"','')) + try: + value = value.decode('ascii', 'ignore').replace('"','') + mac = lc_ldap.crans_utils.format_mac(value) + except: + radiusd.radlog(radiusd.L_ERR, 'Cannot format MAC !') if key == 'User-Name': username = escape_ldap(value.decode('ascii', 'ignore').replace('"','')) + # TODO - # format mac (done by preprocess & hints) # format username (strip .wifi.crans.org) base = u'(objectclass=machine)' - # Search by reported mac, then (if failure) search by username (mac or host) - return conn.search(u'(&%s(macAddress=%s))' % (base, mac)) or \ - conn.search(u'(&%s(|(macAddress=%s)(host=%s.wifi.crans.org)))' % - (base, username, username)) + + if mac is None: + radiusd.radlog(radiusd.L_ERR, 'Cannot read client MAC from AP !') + return [] + + mac = escape_ldap(mac) + username = escape_ldap(username) + + search_strats = [ + # Case 1: Search by mac (reported by AP) + u'(&%s(macAddress=%s))' % (base, mac), + # Case 2: unregistered mac + u'(&%s(macAddress=)(host=%s.wifi.crans.org))' % + (base, username), + ] + + for filter_s in search_strats: + res = conn.search(filter_s, mode='rw') + if res: + break + + return res def get_prise(auth_data): """Extrait la prise""" @@ -91,8 +119,25 @@ def get_prise(auth_data): if bat_num and bat_name and port: return bat_name + "%01d%02d" % (bat_num, port) -# Decorateur utilisé plus tard (same connection) -use_ldap = with_ldap_conn(retries=2, delay=5, constructor=lc_ldap_anonymous) + +@use_ldap +def register_mac(auth_data, machine, conn): + for (key, value) in auth_data: + if key == 'Calling-Station-Id': + try: + value = value.decode('ascii', 'ignore').replace('"','') + mac = lc_ldap.crans_utils.format_mac(value) + except: + radiusd.radlog(radiusd.L_ERR, 'Cannot format MAC !') + if mac is not None: + mac = unicode(mac.lower()) + machine['macAddress'] = mac + machine.history_add(u'auth.py', u'macAddress ( %s )' % mac) + machine.save() + radiusd.radlog(radiusd.L_INFO, 'Mac set') + trigger_generate('komaz', background=True) + else: + radiusd.radlog(radiusd.L_ERR, 'Cannot find MAC') @use_ldap def instantiate(p, conn): @@ -108,15 +153,20 @@ def wifi_authorize(auth_data, conn): champs login et mot de passe qui serviront ensuite à l'authentification (MschapV2/PEAP ou MschapV2/TTLS)""" - items = get_machines(auth_data, conn) + items = get_machines(auth_data) if not items: radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Nobody found') return radiusd.RLM_MODULE_NOTFOUND + if len(items) > 1: - radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Too many results') + radiusd.radlog(radiusd.L_ERR, 'lc_ldap: Too many results (took first)') machine = items[0] + + if '' in machine['macAddress']: + register_mac(auth_data, machine) + proprio = machine.proprio() if isinstance(proprio, lc_ldap.objets.AssociationCrans): @@ -131,8 +181,10 @@ def wifi_authorize(auth_data, conn): radiusd.radlog(radiusd.L_ERR, 'WiFi authentication but machine has no' + 'password') return radiusd.RLM_MODULE_REJECT + password = machine['ipsec'][0].value.encode('ascii', 'ignore') + # TODO: feed cert here return (radiusd.RLM_MODULE_UPDATED, (), ( @@ -150,7 +202,7 @@ def post_auth(auth_data, conn): reason = '' identity = "" #TODO prise = "" #TODO - items = get_machines(auth_data, conn) + items = get_machines(auth_data) decision = 'adherent','' if not items: @@ -162,7 +214,6 @@ def post_auth(auth_data, conn): if isinstance(machine, lc_ldap.objets.machineWifi): decision = 'wifi', '' - print machine['macAddress'][0].value if not machine['ipHostNumber'] or unicode(machine['macAddress'][0]) in test_v6: decision = 'v6only', 'No IPv4' elif machine['ipHostNumber'][0].value in netaddr.IPNetwork('10.2.9.0/24'): @@ -171,14 +222,14 @@ def post_auth(auth_data, conn): for bl in machine.blacklist_actif(): if bl.value['type'] in bl_isolement: - decision = 'isolement', unicode(bl).encode('utf-8') + decision = 'isolement', unicode(bl) if bl.value['type'] in bl_accueil: - decision = 'accueil', unicode(bl).encode('utf-8') + decision = 'accueil', unicode(bl) vlan_name, reason = decision vlan = vlans[vlan_name] radiusd.radlog(radiusd.L_INFO, 'auth.py: %s -> %s [%s%s]' % - (prise, identity, vlan_name, (reason and ': ' + reason)) + (prise, identity, vlan_name, (reason and u': ' + reason).encode(u'utf-8')) ) # @@ -198,7 +249,7 @@ def post_auth(auth_data, conn): # return (0, "Hébergeur non à jour", "accueil") # # - + return radiusd.RLM_MODULE_OK return (radiusd.RLM_MODULE_UPDATED, ( ("Tunnel-Type", "VLAN"), diff --git a/freeradius/test.py b/freeradius/test.py index 1cc5472f..c3467794 100755 --- a/freeradius/test.py +++ b/freeradius/test.py @@ -5,12 +5,17 @@ import auth import sys import time -if len(sys.argv) < 2: +if len(sys.argv) < 2 and False: print "Give me a mac !" sys.exit(1) # Machine à s'authentifier (cerveaulent) -p=(('Calling-Station-Id', sys.argv[1]),) +#p=(('Calling-Station-Id', sys.argv[1]),) + +p=( + ('Calling-Station-Id', 'ba:27:eb:3c:54:d5'), + ('User-Name', 'test18'), +) print repr(auth.wifi_authorize(p)) print "wait for 3s, tu peux aller crasher le serveur pg ou ldap"