Wipe existing reply attributes in rlm_files
Hello, I'm using freeradius 2.1.7. I would like to know if there's a simple way, within a users file, to *replace* the entire set of reply attributes with some others. For example, NONE Foo = "bar", Baz = "bap" # FIXME: delete all reply attributes which have accumulated so far Framed-IP-Address = 1.1.1.1 The idea is that I've already done a database dip using something like rlm_sql, which may have added some reply attributes; but then later logic requires that I need to remove those reply attributes and replace them with a different set (e.g. to L2TP tunnel them somewhere else) I know I could remove specific attributes using -=, but I don't know which attributes might have been added by this point. My current solution is very messy, using two users files. Firstly I set a temporary control list attribute: NONE Foo = "bar", Baz = "bap", Postauth-Action := "XXX" and then next in the authorize { } config I have: if ("%{control:PostAuth-Action}" =~ /./) { deleteall # invoke custom module to clear reply list postauth_attrs # invoke second users file } and finally, in a second users file, I add the new attributes: XXX Framed-IP-Address = 1.1.1.1 I can't even use the standard attr_filter module to delete the existing reply attributes, because when it's invoked in the authorize { } section it acts on the request list, not the reply list. Have I missed an easier way to do this? Thanks, Brian.
On 10/02/2010 10:07 AM, Brian Candler wrote:
Hello, I'm using freeradius 2.1.7.
I would like to know if there's a simple way, within a users file, to *replace* the entire set of reply attributes with some others. For example,
I don't think so.
My current solution is very messy, using two users files. Firstly I set a temporary control list attribute:
Why don't you just do whatever "if()" logic before adding the attributes? You'll probably find this easier in unlang: authorize { ... if (Your-Condition == VALUE) { users1 } else { users2 } } ...that is almost certainly going to be easier and safer than blowing away all the reply attributes (what about Message-Authenticator, or State, or other server-generated stuff, if you were using them?)
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. 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. 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. Regards, Brian.
Brian Candler wrote:
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.
That's what databases are for. And the virtual servers are reloaded on HUP, too, just like the "users" file.
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.
Exactly...
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.
That is nearly always the *wrong* thing to do. It makes no sense to add something, realize you got it wrong, and then replace it with something else. Instead, just figure out the logic so that only the right things are added in the right situation. It will be simpler and easier to understand. 10+ years of experience is behind that opinion. Alan DeKok.
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
participants (3)
-
Alan DeKok -
Brian Candler -
Phil Mayers