FYI : My workaround for freeradius not sending back an Access-Reject on a failed external script

Patric patrict at bluebottle.com
Fri May 25 16:20:39 CEST 2007


Hey guys,

Thought it might interest some of you as to how I worked around the 
problem where freeradius does not return an Access-Reject if my php 
script does not exit successfully (in my case because a user should be 
rejected).

The original code that checks the exit status of the script is this :

src/modules/rlm_exec/rlm_exec.c :

/*
 *  Dispatch an exec method
 */
static int exec_dispatch(void *instance, REQUEST *request)
{
...
        if (result != 0) {
                radlog(L_ERR, "rlm_exec (%s): External script failed",
                       inst->xlat_name);
                return RLM_MODULE_FAIL;
        }
...
        return RLM_MODULE_OK;
}

So basically if my script does not return 0, it failed, regardless of 
its exit status.
According to the RLM_MODULE_* definitions :

enum {
        RLM_MODULE_REJECT,      /* 0 - immediately reject the request */
        RLM_MODULE_FAIL,        /* 1 - module failed, don't reply */
        RLM_MODULE_OK,          /* 2 - the module is OK, continue */
        RLM_MODULE_HANDLED,     /* 3 - the module handled the request, 
so stop. */
        RLM_MODULE_INVALID,     /* 4 - the module considers the request 
invalid. */
        RLM_MODULE_USERLOCK,    /* 5 - reject the request (user is 
locked out) */
        RLM_MODULE_NOTFOUND,    /* 6 - user not found */
        RLM_MODULE_NOOP,        /* 7 - module succeeded without doing 
anything */
        RLM_MODULE_UPDATED,     /* 8 - OK (pairs modified) */
        RLM_MODULE_NUMCODES     /* 9 - How many return codes there are */
};

So if I wanted to authenticate a user I should *actually* be returning 2.
If I wanted to *reject* the user I should be returning 0.

But according to the code above if I return 2 the external script 
failed, and if I return 0, the external script was successful and my 
user is authenticated successfully.

This is how I changed the logic :

I *removed* :
...
        if (result != 0) {
                radlog(L_ERR, "rlm_exec (%s): External script failed",
                       inst->xlat_name);
                return RLM_MODULE_FAIL;
        }
...

And replaced it with :

...
        switch (result) {
        case 0: // Rejected
                return RLM_MODULE_REJECT;
                break;
        case 1: // Failed
                return RLM_MODULE_FAIL;
                break;
        case 2: // OK
                break;
        case 3: // Handled
                return RLM_MODULE_HANDLED;
                break;
        case 4: // Invalid
                return RLM_MODULE_INVALID;
                break;
        case 5: // UserLock
                return RLM_MODULE_USERLOCK;
                break;
        case 6: // Not Found
                return RLM_MODULE_NOTFOUND;
                break;
        case 7: // No Op
                return RLM_MODULE_NOOP;
                break;
        case 8: // Updated
                return RLM_MODULE_UPDATED;
                break;
        case 9: // Num Codes
                return RLM_MODULE_NUMCODES;
                break;
        default: // Fail
                return RLM_MODULE_FAIL;
                break;
        }
...

In this way, if the result is 2 (user is OK), the process will drop out 
of the switch statement, and process the original code for handling a 
successful authentication.

Now in my external script I can do :

exit(2); --> User was accepted.

OR

exit(0); --> User was rejected.


I realise that this is a bit of a contradiction for the external script, 
because for a reject it is exiting successfully, and for a successful 
authentication it is in fact failing with exit code 2. BUT in this way I 
can use the codes determined by freeradius in my external script.

I do not think that this is the actual bug that Alan refered to, but it 
was a problem in my case.
The original code is actually correct in that the external script *did* 
fail, but it was ignoring the exit code to determine what action to take.


I believe that the actual bug is that freeradius does not return a reply 
to the authentication request if the status is set to RLM_MODULE_FAIL.
 From what I could tell the only time that freeradius replies to a 
request is if the status is RLM_MODULE_OK, or RLM_MODULE_REJECT and 
possibly RLM_MODULE_USERLOCK.


I hope that this is understandable, I have the whole scenario in my head 
but its a bit difficult to verbalise...
Please advise if any of my presumptions or understandings are incorrect, 
as I am happy to learn!

Thanks for all your responses to my questions, Im back on track now!

Patrick

----------------------------------------------------------------------
Get a free email address with REAL anti-spam protection.
http://www.bluebottle.com




More information about the Freeradius-Users mailing list