Wipe existing reply attributes in rlm_files

Phil Mayers p.mayers at imperial.ac.uk
Sat Oct 2 14:07:26 CEST 2010


On 10/02/2010 11:05 AM, Brian Candler wrote:
>> Why don't you just do whatever "if()" logic before adding the attributes?
>
> It's complicated :-)
>
> Partly it's policy. We configure as much of this logic in users files as
> possible, because they can be updated without needing to restart radiusd.

The obvious solution to this is SQL, but you're already planning on 
moving to that.

>
> But in future it will be a necessity. The project I'm working on involves
> authenticating users based on some attribute which identifies their physical
> location, not their User-Name.  So decisions you might have made in the past
> solely based on realm and NAS-IP (e.g. tunnel to X) have to be made after a
> database lookup.

We do something similar with per-location MAC auth; when the request 
comes in, the Calling-Station-Id and NAS-IP-Address are fed into an SQL 
stored procedure that does the heavy lifting; a machines get the 
"closest" match VLAN for the given switch, based on a mapping of IPv4 
subnets to vlans, and MAC to IP addresses and fallback zones/vlans.

My point being, the logic is all done in the lookup (but see below for 
how I also permit overriding without attribute removal)

>
> That database lookup may add reply attributes, which will be needed by the
> terminating LNS, but not when tunnel switching.  So if the database
> identifies the user as category X, *and* the request comes from NAS-IP Y,
> then we have to strip the reply attributes and replace with tunnelling ones.

The approach I take is to have the database lookup add a local 
(non-wire) attribute set to the request (not reply) pairs. I then copy 
that (conditionally) into the reply. It more or less works like so:

authorize {
   # do the SQL lookup
   update control {
     Tmp-String-0 := "%{sql:select vlan||','||zone from proc('...')}"
   }
   if (control:Tmp-String-0 =~ /(.+),(.+)/) {
     update request {
       MyVlan = "%{0}"
       MyZone = "%{1}"
     }
   }
   else {
     # SQL failed?
     reject
   }

   # permit manual overrides
   override_files
   if (ok) {
     # do nothing more
   }
   # obviously here you could have elif() statements
   # that generate reply pairs in many different ways
   else {
     update reply {
       Tunnel-Private-Group-Id = "%{MyVlan}"
     }
   }
}

"override_files" is just a "files" module in which we can put things 
which the database module lookup can't (or shouldn't) handle, like 
temporary testing hacks and such. Since we're using a "files" module for 
this, the attribute I add from the database need to go into the request 
pairs, so I can do things like:

DEFAULT	NAS-IP-Address == ..., MyVlan == 1234
	Vendor-Thing = "tagged-vlan=%{MyVlan}"

...and other such junk.

The point of all this is that you can add attributes into the request or 
control pairs, or non-wire attributes into the reply, and then do 
conditional logic on those, and not have to worry about stripping them 
out - for request/control pairs, obviously because they're not sent in 
the reply, and for non-wire reply pairs, because they're not sent on the 
wire.

By "non-wire" I mean anything with an attribute number >255 - such as 
Tmp-String-0, or any other attributes you care to define in a local 
dictionary (FreeRadius reserves 3000-3999 for this purpose)

HTH



More information about the Freeradius-Users mailing list