I've got (what I believe is) an interesting engineering problem to solve. I'm going to oversimplify our problem a bit, so for simplicity sake, we use "Auth-Type := Local" right now with a username and password. We're deploying a new certificate-based method now, and I want to figure out the best way to intergrate the two methods. The problem is that the NAS (Cisco 3000) does the certificate authentication, but then queries radiusd server for *authorization* only. Essentially with doing certificate-based authentication, the NAS sends: User-Name = "geoff" User-Password = "geoff" NAS-Port = 1016 Service-Type = Framed-User Framed-Protocol = PPP Called-Station-Id = "10.1.2.99" Calling-Station-Id = "10.0.33.224" Tunnel-Client-Endpoint:0 = "10.0.33.224" NAS-IP-Address = 10.0.32.138 NAS-Port-Type = Virtual whereas when it's doing regular authentication, it sends the same thing as above, except User-Password = "mysecretpassword". There are no configuration options in the NAS to either restrict the NAS-Port that gets used (ie. cert auth would use ports 1-1000 and regular auth would use 1001-2000), nor is there a way to *apply* a realm to a request (only to strip the realm from the request, which doesn't help me). The only thing the NAS can do that is "helpful" is send cert auth requests to a different UDP port than regular auth requests. To do the first method, I can use 'Auth-Type := Local' and just set the User-Password attribute to the User-Name, or I can use 'Auth-Type := Accept'. Either works just fine, since the NAS is only requesting authorization (ie. is this user in the users file for our NAS). However, because the password it sends is the username, I can't just put two entries in the users file, since anyone doing the "old-style" username/password auth could just enter their username as their password and get access (or more appropriately, joe hacker could user someone's username as that user's password to get unauthorized access). The same NAS is used for both certificate and password auth, so I can't restrict access via the NAS. Also, the same attributes are sent for regular authentication, so I can't differentiate. As mentioned above, I *can* force the NAS to use a different UDP port based on the auth method (ie. certificate auth goes to port 1812 while old-stlye auth goes to port 1645), but I can't tell if there's a way to get radiusd to listen on multiple UDP ports, or if there's a way to determine which UDP port was used in the connection when doing auth (I noticed a Packet-Src-Port attribute in the freeradius.internal dictionary, but I can't tell if there's a way I can use that in the users file). I'm hoping someone might have some insight into the above paragraph. "You'll need to add that" is reasonable insight, so long as that's my only answer - I'm just hoping I can avoid doing that. Thanks!
Geoff Silver wrote:
I've got (what I believe is) an interesting engineering problem to solve. I'm
Hmm - you're right, interesting
options in the NAS to either restrict the NAS-Port that gets used (ie. cert auth would use ports 1-1000 and regular auth would use 1001-2000), nor is there a way to *apply* a realm to a request (only to strip the realm from the request, which doesn't help me). The only thing the NAS can do that is "helpful" is send cert auth requests to a different UDP port than regular auth requests.
"Helpful" in quotes indeed!
a Packet-Src-Port attribute in the freeradius.internal dictionary, but I
I assume you mean Packet-Dst-Port, but yes that would be the way to do it. Looking at it, it appears this is in CVS head but not in my tarball of 1.1.0. doc/variables.txt in a CVS checkout lists Packet-Dst-Port as supported and it's in the xlat_packet function. What I can't figure out is how you might do this: DEFAULT %{request:Packet-Dst-Port}==1234, Autz-Type := "cert" ...i.e. have an expansion on the left hand side. I'm not sure you can, but the code is quite big and I've only scanned it. What you can do (in CVS head) is use the following in the hints file (which is actually quite appropriate): DEFAULT User-Name =~ "^(.*)$" Hint = "%{request:Packet-Dst-Port}" ...the have the "users" file read: DEFAULT Hint=="THEDESTPORT", Auth-Type := Accept ...and of course, add a 2nd listen section to the "radiusd.conf": listen { ipaddr = * port = THEDESTPORT type = auth } You can get more complex if you need to using Autz-Type based on the hint, or whatever. Hope that helps.
Phil Mayers wrote:
Geoff Silver wrote:
a Packet-Src-Port attribute in the freeradius.internal dictionary, but I
I assume you mean Packet-Dst-Port, but yes that would be the way to do it. Yeah.
Looking at it, it appears this is in CVS head but not in my tarball of 1.1.0. doc/variables.txt in a CVS checkout lists Packet-Dst-Port as supported and it's in the xlat_packet function. Okay, I'll take a look at my 1.1.0 and check out the CVS tree as well when I get back into the office and see. The only place I noticed it in 1.1.0 was in the dictionary.
What I can't figure out is how you might do this:
DEFAULT %{request:Packet-Dst-Port}==1234, Autz-Type := "cert"
...i.e. have an expansion on the left hand side. I'm not sure you can, but the code is quite big and I've only scanned it.
What you can do (in CVS head) is use the following in the hints file (which is actually quite appropriate): Cool. I'll give that a shot.
DEFAULT User-Name =~ "^(.*)$" Hint = "%{request:Packet-Dst-Port}"
...the have the "users" file read:
DEFAULT Hint=="THEDESTPORT", Auth-Type := Accept
...and of course, add a 2nd listen section to the "radiusd.conf":
listen { ipaddr = * port = THEDESTPORT type = auth }
Does that work? I *thought* I tried that and found that it only listened on the first port (but I may be entirely mistaken). Again, I'll try when I get back in the office on Tuesday, if I don't have an opportunity to hop on our vpn and try it earlier. I'll let you know how it goes.
You can get more complex if you need to using Autz-Type based on the hint, or whatever.
Hope that helps. - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html Thanks!
Hi Phil (et al), In case others on the list are interested, I was able to get this working with last nights CVS checkout by setting a hints entry of: DEFAULT User-Name =~ "^(.*)$" Hint = "Port-%{request:Packet-Dst-Port}" And users entries of: geoff Auth-Type := Accept, Huntgroup-Name == "office", Hint == "Port-1645" geoff Auth-Type := Local, User-Password == "mypassword", Huntgroup-Name == "office", Hint == "Port-1812" I went through the diff's between production 1.1.0 and CVS and ended up creating the following patch, based on the CVS 2.0.0pre0 code. Are there any developers on this list, and if so, would anyone be willing to add the following patch into the next 1.1.x release (I hate to subscribe to the -devel list just to ask if anyone will include this patch)? --- src/main/xlat.c.orig 6 Feb 2006 20:52:20 -0000 1.1 +++ src/main/xlat.c 21 Feb 2006 21:17:56 -0000 @@ -196,6 +196,10 @@ * FIXME: Add SRC/DST IP address! */ if (packet) { + VALUE_PAIR localvp; + + localvp.strvalue[0] = 0; + switch (da->attr) { case PW_PACKET_TYPE: { @@ -210,12 +214,26 @@ return strlen(out); } break; + + case PW_PACKET_SRC_PORT: + localvp.attribute = da->attr; + localvp.lvalue = packet->src_port; + break; + + case PW_PACKET_DST_PORT: + localvp.attribute = da->attr; + localvp.lvalue = packet->dst_port; + break; default: + return 0; break; } - } + localvp.type = da->type; + return valuepair2str(out, outlen, &localvp, + da->type, func); + } /* * Not found, die. */ --- src/include/radius.h.orig 6 Feb 2006 20:52:20 -0000 1.1 +++ src/include/radius.h 21 Feb 2006 21:18:29 -0000 @@ -183,8 +183,9 @@ #define PW_REWRITE_RULE 1078 #define PW_SQL_GROUP 1079 #define PW_RESPONSE_PACKET_TYPE 1080 -#define PW_PACKET_DST_PORT 1081 #define PW_MS_CHAP_USE_NTLM_AUTH 1082 +#define PW_PACKET_SRC_PORT 1086 +#define PW_PACKET_DST_PORT 1087 /* * Integer Translations Phil Mayers wrote:
I assume you mean Packet-Dst-Port, but yes that would be the way to do it.
Looking at it, it appears this is in CVS head but not in my tarball of 1.1.0. doc/variables.txt in a CVS checkout lists Packet-Dst-Port as supported and it's in the xlat_packet function.
What I can't figure out is how you might do this:
DEFAULT %{request:Packet-Dst-Port}==1234, Autz-Type := "cert"
...i.e. have an expansion on the left hand side. I'm not sure you can, but the code is quite big and I've only scanned it.
What you can do (in CVS head) is use the following in the hints file (which is actually quite appropriate):
DEFAULT User-Name =~ "^(.*)$" Hint = "%{request:Packet-Dst-Port}"
...the have the "users" file read:
DEFAULT Hint=="THEDESTPORT", Auth-Type := Accept
the request, which doesn't help me). The only thing the NAS can do that is "helpful" is send cert auth requests to a different UDP port than regular auth requests.
Perhaps there are new features that can take care of this for you in one place, but if not, you can just run two radiusd instances. One for "oldschool" and one for cert. For example, say your raddb dir is in /etc/raddb now. You would create two subdirs of that directory mkdir /etc/raddb/oldschoool mkdir /etc/raddb/cert and perhaps for logging seperately as well mkdir /var/log/radius/oldschool mkdir /var/log/radius/cert cp all the files from raddb to the two directories. Modify the top of radiusd.conf to point to the new directories for raddbdir, confdir, logdir, etc.. Modify the listen or port arguments to make one listen on 1645 and the other on 1812. Then modify the rest of it, such as the users file, to do what you want for each seperate instance. Then modify your startup script to fire off two instances using the -d option, and make sure you get both instances as well no stop/restarts. eg: /pathto/radiusd -d /etc/raddb/oldschool /pathto/radiusd -d /etc/raddb/cert That will give you two seperate instances. One will be configured to only handle oldschool logins and the other to only handle certs. It will be another port/process you'll have to monitor, but it should give you what you want.
Hi Dusty, Yeah, I had considered running two radiusd instances, actually, but it felt less than ideal. Part of the problem is that our radius infrastructure is spread across two dozen servers around the world, and multiple radiusd's give us more moving parts (two /etc/raddb configs, two sets of users files, two daemons to worry about, etc). We have some tools to manage distribution of configs, users files, etc, but as-is they would probably require significant changes. Hopefully I can make freeradius do what I want... if not, I may end up taking your advice ;-) Thanks. Dusty Doris wrote:
the request, which doesn't help me). The only thing the NAS can do that is "helpful" is send cert auth requests to a different UDP port than regular auth requests.
Perhaps there are new features that can take care of this for you in one place, but if not, you can just run two radiusd instances. One for "oldschool" and one for cert.
For example, say your raddb dir is in /etc/raddb now.
You would create two subdirs of that directory
mkdir /etc/raddb/oldschoool mkdir /etc/raddb/cert
and perhaps for logging seperately as well
mkdir /var/log/radius/oldschool mkdir /var/log/radius/cert
cp all the files from raddb to the two directories.
Modify the top of radiusd.conf to point to the new directories for raddbdir, confdir, logdir, etc.. Modify the listen or port arguments to make one listen on 1645 and the other on 1812.
Then modify the rest of it, such as the users file, to do what you want for each seperate instance.
Then modify your startup script to fire off two instances using the -d option, and make sure you get both instances as well no stop/restarts.
eg:
/pathto/radiusd -d /etc/raddb/oldschool /pathto/radiusd -d /etc/raddb/cert
That will give you two seperate instances. One will be configured to only handle oldschool logins and the other to only handle certs. It will be another port/process you'll have to monitor, but it should give you what you want.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
participants (3)
-
Dusty Doris -
Geoff Silver -
Phil Mayers