Earlier today I was throwing together a five-minute RADIUS server using FreeRadius. The idea was to quickly get it to authenticate users from an existing MySQL table on a database server.

Unfortunately the existing table only has the user’s password in an MD5 format, and as far as I’m aware FreeRadius doesn’t deal with MD5 passwords except in EAP (which this is not). Herein lies the dodgy hack.

First, as this system is a throwaway that only needs to do basic authentication - let’s dodge up a quick view with the data in the following standard FreeRadius table. Please note that field names have been changed to protect IP.

CREATE VIEW `radcheck` AS SELECT primkey AS id, name_user AS UserName, 'Cleartext-Password' AS Attribute, ':=' AS op, password AS Value FROM otherdb.othertable;

Strictly the above isn’t necessary, as you can configure the FreeRadius queries as you wish. The aim of this is to minimise the changes made to the freeradius configuration.

Once that’s done, I modified the FreeRadius configuration so instead of the standard query which grabs all the fields out of the table, to do the following:

authorize_check_query = "SELECT id, UserName, Attribute, IF( MD5('${User-Password}') = Value, ${User-Password}, Value ) as Value, op FROM ${authcheck_table} WHERE Username = '%{SQL-User-Name}' ORDER BY id"

This dodgy little statement forces MySQL to compare the MD5 of the plaintext password in the radius request against the MD5 in the database. If they match, it will return the specified plaintext (which will match later) and pass. Otherwise it will return the MD5 password from the table.

I should state that this actually allows two passwords for the user, their actual password or the MD5 of their password. For the purposes of this exercise the tradeoff was acceptable (though there are arguments that this isn’t so bad anyway).

Really dirty hack, but I thought it was a novel solution to the problem :P