User Collision in FreeRadius ---------------------------- 0. INTRODUCTION A. What is it? User collision is the ability to uniquely authenticate duplicate usernames in radius. In addition, it provides resources to correctly identify each duplicate user in the accounting logs. B. Who needs it and why? Many ISPs are acquiring other ISPs in local or remote areas. This causes problems with centralizing services such as radius because of the overlap in usernames between ISPs. For example: o ISP A (with 10,000 users) acquires ISP B (with 1,000 users). o ISP A determines that 375 of ISP B's 1,000 usernames conflict with usernames already in use at ISP A (eg 'foo' is valid username on both ISPs) o ISP A, therefore, cannot merge its user files with ISP B and centralize radius Now, about now, many of you are thinking, "what about realms?" Well, realms are great, but, in general, it will require the end user to add "@domain.com", which is a pain. It means ISP A has to call 375 people and tell them to add that to their login name. And now some of you are thinking, "why couldn't you add the realm in the server based on some other attribute (such as NAS-IP or Calling-Station)?" The answer is, you could, but both of those solutions are a pill to maintain. For example, what if you want to merge the huntgroups (and NASs) of ISP A and ISP B? Then the NAS-IP method falls apart. And god forbid the user call from a different number or change their line for Calling-Station. So how to solve it? Enter user collision code in radius... C. How does it work? Currently, it only works when authenticating users via the following methods in FreeRadius: o 'users' file ( Auth-Types 'Local' and 'Crypt-Local' _ONLY_ ) o cached password (and shadow) file users o rlm_fastusers module (see README.rlm_fastusers) That's it so far. Perhaps other module authors will include it in their code later, but that is for them to decide. Btw, the reason user collision cannot be implemented (efficiently) on a non-cached /etc/passwd file is because getpwnam() will always return the first user it finds with a matching username. Thus, if you're going to use the /etc/passwd file, you MUST set 'cache = yes' in your radiusd.conf. Or, you could always just put duplicate usernames in the 'users' files, but you should probably be caching anyway if you want a speedy server :) 1. Authentication It currently works by using the password of the user to uniquely identify and auth- enticate them. Example: ISP A user 'foo' has password 'bar' ISP B user 'foo' has password 'bleah' If the user logs in with 'bar' as their password, their login will be accepted and they will get the reply attributes associated with what you've entered for the user 'foo' password 'bar' entry. If the user logs in with 'bleah' as the password, again, they'll be authenticated, but they will get the reply attributes associated with user 'foo' password 'bleah'. So, what happens if two users have the same password? IT BREAKS. Well, ok, it doesn't "break", but every user with the associated pass will get the same reply attributes, causing grief for you. THE CODE DOES NOT CHECK FOR THIS, THAT IS YOUR JOB! NOTE: Again, user collision authentication *depends* on the passwords being distinct! So the security minded among us are now agast. I'm not much for this method myself, but trust me, the corporate folks are gonna love it. And it's not inherently insecure as long as the passwords remain different. 2. Accounting Ok, so now, how can we tell in the accounting logs which user 'foo' logged in? Well, again, you have a little work to do. The code identifies the user via a unique value assigned to the 'Class' reply attribute in the users file. For example: foo Auth-Type := Local, User-Password == "bar" Class = 0x0001 foo Auth-Type := Local, User-Password == "bleah" Class = 0x0002 Now, you'd add other attributes as well, but let's just start with 'Class' by itself as a reply. When a user 'foo' logs in with password 'bar', the 'Class=0x0001' reply item gets sent back to the NAS they dialed into. The NAS then adds 'Class=0x0001' to the Accounting 'Start' packet it sends for that user, thus uniquely identifying *this* 'foo' in the your accounting logs. If the user 'foo' logs in with password 'bleah', you will get 'Class=0x0002' in your accounting logs. Now, again, you should note that it is *your job* to make sure the 'Class' values are different for each user. If you don't, I can assure you the phones will ring off the hook when bitchy users get their bills. Obviously, this method works only for users in your 'users' files. If you are using a cached passwd file, then the "Full name" field in the passwd file you cached will be passed back to the NAS as the value of 'Class'. Example: /etc/passwd -> test:x:500:500:0x1001:/dev/null:/dev/null In this case, "0x1001" will be passed as the value for the 'Class' attribute when the Auth-Accept packet gets sent back to the NAS, and then you should see 'Class=0x1001' for that user in your accounting logs. Once again, it is your job to ensure that these Class values are unique for each user. D. *Does* it work? As of 10-01-2000, it is *extremely alpha*. If you find bugs, by all means let met know at jeff@apex.net, but make sure you include relavent sections of your 'users' file and debug output from the server (radiusd -X). 1. USAGE Set 'usercollide=yes' in your radiusd.conf and either restart or kill -HUP radiusd. 2. CAVEATS Currently does not work with all modules (ie, sql, ldap, etc). 3. ACKNOWLEDGEMENT Jeff Carneal - Author Alan DeKok - for telling me about the 'Class' attribute :)