Hi, Currently, I'm playing with freeradius 2 to evaluate the new unlang features (using CVS source from today). I figured out the following setup for an unlang if-else construct matching on a module return. I'm just wondering if this is the most elegant solution currently possible. Comments welcome.
server {
authorize { if ("%{NAS-IP-Address}" == '') { update request { NAS-IP-Address = "%{Client-IP-Address}" } } auth_log users pap }
authenticate { Auth-Type PAP { pap { ok = 1 # don't stop processing reject = 1 } if (reject) { ok = 1 # preserve PAP result in case the if-clause evaluates to false update reply { Reply-Message := "Wrong PAP password." } } elsif (ok) { update reply { Reply-Message := "Welcome." } } } }
}
Enrik
Enrik Berkhan wrote:
I figured out the following setup for an unlang if-else construct matching on a module return. I'm just wondering if this is the most elegant solution currently possible. Comments welcome.
You can *match* on a module return code. You can only change the return code by using the method in "doc/configurable_failover". Note that *that* method works only with modules, and *not* inside of an "unlang" block. ...
pap { ok = 1 # don't stop processing
This will work: pap is a module.
reject = 1 } if (reject) { ok = 1 # preserve PAP result in case the if-clause evaluates to false
This will not work: "if" is not a module. The comment is also wrong. The contents of the "if" block are evaluated ONLY if the "if" evaluates to true. So setting "ok = 1" (even if it worked) would happen only when the "if" evaluates to true. On top of that, "if", "else", and "elsif" don't modify the module return code. Ever. The module return code is changed only by modules, *or* by the "update" command, which sets the return code to "updated". What you probably want here is: pap { ok = 1 reject = 1 } if (ok) { update reply { Reply-Message := "Welcome." } } elsif (reject) { update reply { Reply-Message := "Wrong PAP password." } reject # over-rides the "updated" flag. } .... Hmm... there should probably be a flag to the "update" command to tell it to *not* change the module return code. Or, better yet, the "update" command shouldn't change the module return code. That can be done with the "always" module. There should also probably be a flag to tell it to delete all of the attributes in a list. Maybe: update -reply { ... } Alan DeKok.
Hi, Alan DeKok schrieb:
Enrik Berkhan wrote:
reject = 1 } if (reject) { ok = 1 # preserve PAP result in case the if-clause evaluates to false
This will not work: "if" is not a module. The comment is also wrong.
But exactly adding the "ok = 1" makes it work. Have you tried it? May be it's a bug though ... :)
The contents of the "if" block are evaluated ONLY if the "if" evaluates to true. So setting "ok = 1" (even if it worked) would happen only when the "if" evaluates to true.
But it takes something from the child block after the unroll: label in modcall.c. That's why I have tried the above. Maybe this is not correct for if/elsif?
unroll: /* * The child's action says return. Do so. */ if (child->actions[myresult] == MOD_ACTION_RETURN) {
Actually, I've changed it to "ok = 2" to override the "updated" return from the Reply-Message update in the elsif section.
What you probably want here is:
pap { ok = 1 reject = 1 } if (ok) { update reply { Reply-Message := "Welcome." }
} elsif (reject) { update reply { Reply-Message := "Wrong PAP password." } reject # over-rides the "updated" flag. } ....
You are right, that's like I wanted it, but it didn't work. So may be the if-processing is still buggy then. Enrik
Enrik Berkhan wrote:
But exactly adding the "ok = 1" makes it work. Have you tried it? May be it's a bug though ... :)
Hmm... then I'm not sure I understand what the code is doing. ...
But it takes something from the child block after the unroll: label in modcall.c. That's why I have tried the above. Maybe this is not correct for if/elsif?
The if/elsif blocks should force the current return code to be the last one used. I think it worked by accident, so it's good to fix the code to make it work on purpose. ...
What you probably want here is: ... You are right, that's like I wanted it, but it didn't work. So may be the if-processing is still buggy then.
Hmm... putting "ok = 1" in an "if" section doesn't do *anything*. It's accepted by the parser, but it doesn't do anything. OK... after a bit of examination, what works is: pap { ok = 1 reject = 1 } if (ok) { update reply { Reply-Message := "Welcome." } ok } elsif (reject) { update reply { Reply-Message := "Wrong PAP password." } reject # over-rides the "updated" flag. } It's not intuitive, but it works. But really, all of that logic belongs in the "post-auth" section. That's what it's there for. Use the "Post-Auth-Type Reject" section. It's documented in radiusd.conf. Alan DeKok.
...
But really, all of that logic belongs in the "post-auth" section. That's what it's there for. Use the "Post-Auth-Type Reject" section. It's documented in radiusd.conf.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
So return codes work properly again now ? Or do they semi work from before ? -- Arran Cudbard-Bell (A.Cudbard-Bell@sussex.ac.uk) Authentication, Authorisation and Accounting Officer Infrastructure Services | ENG1 E1-1-08 University Of Sussex, Brighton EXT:01273 873900 | INT: 3900
Arran Cudbard-Bell wrote:
So return codes work properly again now ? Or do they semi work from before ?
I'm not sure what you mean by that. module { notfound = 1 ... } works. It's always worked. What also works now is: if (notfound) { ... } What *doesn't* work is: if (...) { ok = 1 ... } It's never worked. The original question was about implementing logic of "if auth, do X, if reject, do Y". That's what the "post-auth" section is for. Doing it in the "authenticate" section is wrong. Alan DeKok.
Alan DeKok wrote:
Arran Cudbard-Bell wrote:
So return codes work properly again now ? Or do they semi work from before ?
What also works now is:
if (notfound) { ... }
Yes so using return codes in unlang statements now works , which is what i was wondering. so module_foo if(fail){ module_bar } Though I suppose you could just use failover failover { load-balance { sql1 sql2 sql3 } emergency_users } -- Arran Cudbard-Bell (A.Cudbard-Bell@sussex.ac.uk) Authentication, Authorisation and Accounting Officer Infrastructure Services | ENG1 E1-1-08 University Of Sussex, Brighton EXT:01273 873900 | INT: 3900
Alan DeKok schrieb:
Enrik Berkhan wrote:
But exactly adding the "ok = 1" makes it work. Have you tried it? May be it's a bug though ... :)
Hmm... then I'm not sure I understand what the code is doing.
Currently, it works like so (if/elsif, with if condition evaluating to FALSE): In modcall(), modcall.c lines 362ff the if-condition is evaluated for if and elsif blocks. If the condition evaluates to false, goto unroll. In modcall(), modcall.c lines 564ff (label unroll:), the child->actions[] are used to determine the next step. For MOD_ACTION_RETURN and MOD_ACTION_REJECT, which happen to be default actions in the authenticate action even for if-blocks, goto do_return. So, if an if-condition evaluates to FALSE within the authenticate section, the flow stops after evaluating the if-condition via goto unroll, goto do_return and never ever evaluates the elsif. And yes, the child->actions can be set in the if-block. So, I think, if/elsif/else-blocks either need other defaults for their actions[] or if/elsif/else-blocks need another unroll: mechanism :) But I don't understand enough of the unlang-processing to provide a complete solution, sorry. I could provide very simple example configs to test the behaviour, though, on request. HTH, Enrik
Enrik Berkhan wrote:
Alan DeKok schrieb:
Enrik Berkhan wrote:
But exactly adding the "ok = 1" makes it work. Have you tried it? May be it's a bug though ... :) Hmm... then I'm not sure I understand what the code is doing.
Currently, it works like so (if/elsif, with if condition evaluating to FALSE):
After looking at it a little more: if (...) { ok = 1 } That works because "ok" is a module name, and the "= 1" is ignored. But it doesn't do what you want. I've changed the code so it now prints an error.
And yes, the child->actions can be set in the if-block.
Nope. See the above bug. It *looks* like they can be set, bit it doesn't work. The actions are set ONLY inside of a module section, such as sql { ok = 1 ... } *everywhere* else they don't work.
So, I think, if/elsif/else-blocks either need other defaults for their actions[] or if/elsif/else-blocks need another unroll: mechanism :)
They should just start off with the result of the previous action. I've committed a patch to make them do this. If a module inside of an "if" block changes the result, that's OK. But the *default* for an "if" block is to start off with the previous result. Please check current CVS. In cases where it doesn't work, it should now print an error. This means that configurations you *think* work, but which don't really work, will now print an error. Alan DeKok.
Alan DeKok schrieb:
Please check current CVS. In cases where it doesn't work, it should now print an error. This means that configurations you *think* work, but which don't really work, will now print an error.
Ok, I've tried it, but there is no change. I include my sample config that you can try it yourself. I'm quite sure that I've included the patch from CVS to modcall.c and actually have re-compiled the server:
# strings /usr/sbin/freeradius | grep modcall.c $Id: modcall.c,v 1.86 2007/07/05 15:01:21 aland Exp $
But maybe I've made a mistake, so please verify my results. Debuglog with cumbersome workaround enabled:
Thu Jul 5 20:51:34 2007 : Info: Starting - reading configuration files ... Thu Jul 5 20:51:34 2007 : Debug: read_config_files: reading dictionary Thu Jul 5 20:51:34 2007 : Debug: main { Thu Jul 5 20:51:34 2007 : Debug: prefix = "/usr" Thu Jul 5 20:51:34 2007 : Debug: localstatedir = "/var" Thu Jul 5 20:51:34 2007 : Debug: logdir = "/var/log/freeradius" Thu Jul 5 20:51:34 2007 : Debug: libdir = "/usr/lib/freeradius" Thu Jul 5 20:51:34 2007 : Debug: radacctdir = "/var/log/freeradius/radacct" Thu Jul 5 20:51:34 2007 : Debug: hostname_lookups = no Thu Jul 5 20:51:34 2007 : Debug: snmp = no Thu Jul 5 20:51:34 2007 : Debug: max_request_time = 30 Thu Jul 5 20:51:34 2007 : Debug: cleanup_delay = 5 Thu Jul 5 20:51:34 2007 : Debug: max_requests = 1024 Thu Jul 5 20:51:34 2007 : Debug: allow_core_dumps = no Thu Jul 5 20:51:34 2007 : Debug: log_stripped_names = no Thu Jul 5 20:51:34 2007 : Debug: log_file = "/var/log/freeradius/radius.log" Thu Jul 5 20:51:34 2007 : Debug: log_auth = yes Thu Jul 5 20:51:34 2007 : Debug: log_auth_badpass = yes Thu Jul 5 20:51:34 2007 : Debug: log_auth_goodpass = yes Thu Jul 5 20:51:34 2007 : Debug: pidfile = "/var/run/freeradius/freeradius.pid" Thu Jul 5 20:51:34 2007 : Debug: user = "freerad" Thu Jul 5 20:51:34 2007 : Debug: group = "freerad" Thu Jul 5 20:51:34 2007 : Debug: checkrad = "/usr/sbin/checkrad" Thu Jul 5 20:51:34 2007 : Debug: debug_level = 0 Thu Jul 5 20:51:34 2007 : Debug: proxy_requests = no Thu Jul 5 20:51:34 2007 : Debug: security { Thu Jul 5 20:51:34 2007 : Debug: max_attributes = 200 Thu Jul 5 20:51:34 2007 : Debug: reject_delay = 0 Thu Jul 5 20:51:34 2007 : Debug: status_server = yes Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: listen { Thu Jul 5 20:51:34 2007 : Debug: type = "auth" Thu Jul 5 20:51:34 2007 : Debug: ipaddr = * Thu Jul 5 20:51:34 2007 : Debug: port = 0 Thu Jul 5 20:51:34 2007 : Debug: client 172.27.128.219 { Thu Jul 5 20:51:34 2007 : Debug: secret = "testing123" Thu Jul 5 20:51:34 2007 : Debug: shortname = "localextern" Thu Jul 5 20:51:34 2007 : Debug: nastype = "other" Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: client 127.0.0.1 { Thu Jul 5 20:51:34 2007 : Debug: secret = "testing123" Thu Jul 5 20:51:34 2007 : Debug: shortname = "localhost" Thu Jul 5 20:51:34 2007 : Debug: nastype = "other" Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: radiusd: entering modules setup Thu Jul 5 20:51:34 2007 : Debug: radiusd: Library search path is /usr/lib/freeradius Thu Jul 5 20:51:34 2007 : Debug: modules: Not loading preacct{} section Thu Jul 5 20:51:34 2007 : Debug: modules: Not loading accounting{} section Thu Jul 5 20:51:34 2007 : Debug: modules: Not loading pre-proxy{} section Thu Jul 5 20:51:34 2007 : Debug: modules: Not loading post-proxy{} section Thu Jul 5 20:51:34 2007 : Debug: server { Thu Jul 5 20:51:34 2007 : Debug: modules { Thu Jul 5 20:51:34 2007 : Debug: Module: Checking authenticate {...} for more modules to load Thu Jul 5 20:51:34 2007 : Debug: (Loaded rlm_pap, checking if it's valid) Thu Jul 5 20:51:34 2007 : Debug: Module: Linked to module rlm_pap Thu Jul 5 20:51:34 2007 : Debug: Module: Instantiating pap Thu Jul 5 20:51:34 2007 : Debug: pap { Thu Jul 5 20:51:34 2007 : Debug: encryption_scheme = "auto" Thu Jul 5 20:51:34 2007 : Debug: auto_header = yes Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: >>> CALLING EVALUATE ok) Thu Jul 5 20:51:34 2007 : Debug: >>> LOOKING AT ok) Thu Jul 5 20:51:34 2007 : Debug: >>> I0 23:ok Thu Jul 5 20:51:34 2007 : Debug: >>> EVALUATE 0 ::):: Thu Jul 5 20:51:34 2007 : Debug: >>> AT EOL2a Thu Jul 5 20:51:34 2007 : Debug: >>> EVALUATE RETURNED ::):: Thu Jul 5 20:51:34 2007 : Debug: >>> AT EOL Thu Jul 5 20:51:34 2007 : Debug: >>> CALLING EVALUATE reject) Thu Jul 5 20:51:34 2007 : Debug: >>> LOOKING AT reject) Thu Jul 5 20:51:34 2007 : Debug: >>> I0 23:reject Thu Jul 5 20:51:34 2007 : Debug: >>> EVALUATE 0 ::):: Thu Jul 5 20:51:34 2007 : Debug: >>> AT EOL2a Thu Jul 5 20:51:34 2007 : Debug: >>> EVALUATE RETURNED ::):: Thu Jul 5 20:51:34 2007 : Debug: >>> AT EOL Thu Jul 5 20:51:34 2007 : Debug: Module: Checking authorize {...} for more modules to load Thu Jul 5 20:51:34 2007 : Debug: (Loaded rlm_files, checking if it's valid) Thu Jul 5 20:51:34 2007 : Debug: Module: Linked to module rlm_files Thu Jul 5 20:51:34 2007 : Debug: Module: Instantiating files Thu Jul 5 20:51:34 2007 : Debug: files { Thu Jul 5 20:51:34 2007 : Debug: usersfile = "/etc/freeradius/users" Thu Jul 5 20:51:34 2007 : Debug: acctusersfile = "/dev/null" Thu Jul 5 20:51:34 2007 : Debug: preproxy_usersfile = "/dev/null" Thu Jul 5 20:51:34 2007 : Debug: compat = "no" Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: Initializing the thread pool... Thu Jul 5 20:51:34 2007 : Debug: thread pool { Thu Jul 5 20:51:34 2007 : Debug: start_servers = 5 Thu Jul 5 20:51:34 2007 : Debug: max_servers = 32 Thu Jul 5 20:51:34 2007 : Debug: min_spare_servers = 3 Thu Jul 5 20:51:34 2007 : Debug: max_spare_servers = 10 Thu Jul 5 20:51:34 2007 : Debug: max_requests_per_server = 0 Thu Jul 5 20:51:34 2007 : Debug: cleanup_delay = 5 Thu Jul 5 20:51:34 2007 : Debug: max_queue_size = 65536 Thu Jul 5 20:51:34 2007 : Debug: } Thu Jul 5 20:51:34 2007 : Debug: Thread spawned new child 1. Total threads in pool: 1 Thu Jul 5 20:51:34 2007 : Debug: Thread 1 waiting to be assigned a request Thu Jul 5 20:51:34 2007 : Debug: Thread spawned new child 2. Total threads in pool: 2 Thu Jul 5 20:51:34 2007 : Debug: Thread 2 waiting to be assigned a request Thu Jul 5 20:51:34 2007 : Debug: Thread spawned new child 3. Total threads in pool: 3 Thu Jul 5 20:51:34 2007 : Debug: Thread 3 waiting to be assigned a request Thu Jul 5 20:51:34 2007 : Debug: Thread spawned new child 4. Total threads in pool: 4 Thu Jul 5 20:51:34 2007 : Debug: Thread 4 waiting to be assigned a request Thu Jul 5 20:51:34 2007 : Debug: Thread spawned new child 5. Total threads in pool: 5 Thu Jul 5 20:51:34 2007 : Debug: Thread 5 waiting to be assigned a request Thu Jul 5 20:51:34 2007 : Debug: Thread pool initialized Thu Jul 5 20:51:34 2007 : Debug: Listening on authentication address * port 1812 Thu Jul 5 20:51:34 2007 : Info: Ready to process requests. Thu Jul 5 20:51:34 2007 : Debug: Nothing to do. Sleeping until we see a request. rad_recv: Access-Request packet from host 127.0.0.1 port 53827, id=190, length=44 Thu Jul 5 20:42:08 2007 : Debug: Threads: total/active/spare threads = 5/0/5 Thu Jul 5 20:42:08 2007 : Debug: Thread 1 got semaphore Thu Jul 5 20:42:08 2007 : Debug: Thread 1 handling request 0, (1 handled so far) User-Name = "john" User-Password = "secret" Thu Jul 5 20:42:08 2007 : Debug: +- entering group authorize Thu Jul 5 20:42:08 2007 : Debug: modsingle[authorize]: calling files (rlm_files) for request 0 Thu Jul 5 20:42:08 2007 : Debug: users: Matched entry john at line 1 Thu Jul 5 20:42:08 2007 : Debug: modsingle[authorize]: returned from files (rlm_files) for request 0 Thu Jul 5 20:42:08 2007 : Debug: ++[files] returns ok Thu Jul 5 20:42:08 2007 : Debug: modsingle[authorize]: calling pap (rlm_pap) for request 0 Thu Jul 5 20:42:08 2007 : Debug: modsingle[authorize]: returned from pap (rlm_pap) for request 0 Thu Jul 5 20:42:08 2007 : Debug: ++[pap] returns updated Thu Jul 5 20:42:08 2007 : Debug: rad_check_password: Found Auth-Type Thu Jul 5 20:42:08 2007 : Debug: auth: type "PAP" Thu Jul 5 20:42:08 2007 : Debug: +- entering group PAP Thu Jul 5 20:42:08 2007 : Debug: ++- entering group pap-with-message Thu Jul 5 20:42:08 2007 : Debug: modsingle[authenticate]: calling pap (rlm_pap) for request 0 Thu Jul 5 20:42:08 2007 : Debug: rlm_pap: login attempt with password secret Thu Jul 5 20:42:08 2007 : Debug: rlm_pap: Using clear text password. Thu Jul 5 20:42:08 2007 : Debug: rlm_pap: User authenticated successfully Thu Jul 5 20:42:08 2007 : Debug: modsingle[authenticate]: returned from pap (rlm_pap) for request 0 Thu Jul 5 20:42:08 2007 : Debug: +++[pap] returns ok Thu Jul 5 20:42:08 2007 : Debug: +++? if (ok) Thu Jul 5 20:42:08 2007 : Debug: >>> CALLING EVALUATE ok) Thu Jul 5 20:42:08 2007 : Debug: >>> LOOKING AT ok) Thu Jul 5 20:42:08 2007 : Debug: ? Evaluating "ok" -> TRUE Thu Jul 5 20:42:08 2007 : Debug: >>> I0 23:ok Thu Jul 5 20:42:08 2007 : Debug: >>> EVALUATE 1 ::):: Thu Jul 5 20:42:08 2007 : Debug: >>> AT EOL2a Thu Jul 5 20:42:08 2007 : Debug: >>> EVALUATE RETURNED ::):: Thu Jul 5 20:42:08 2007 : Debug: >>> AT EOL Thu Jul 5 20:42:08 2007 : Debug: +++? if (ok) -> TRUE Thu Jul 5 20:42:08 2007 : Debug: +++- entering if (ok) Thu Jul 5 20:42:08 2007 : Debug: ::: FROM 1 TO 0 MAX 1 Thu Jul 5 20:42:08 2007 : Debug: ::: Examining Reply-Message Thu Jul 5 20:42:08 2007 : Debug: ::: APPENDING Reply-Message FROM 0 TO 0 Thu Jul 5 20:42:08 2007 : Debug: ::: TO in 0 out 1 Thu Jul 5 20:42:08 2007 : Debug: ::: to[0] = Reply-Message Thu Jul 5 20:42:08 2007 : Debug: ++++[reply] returns updated Thu Jul 5 20:42:08 2007 : Debug: +++- if (ok) returns updated Thu Jul 5 20:42:08 2007 : Debug: +++ ... skipping elsif for request 0: Preceding "if" was taken Thu Jul 5 20:42:08 2007 : Debug: ++- group pap-with-message returns ok Thu Jul 5 20:42:08 2007 : Auth: Login OK: [john/secret] (from client localhost port 0) Sending Access-Accept of id 190 to 127.0.0.1 port 53827 Reply-Message := "pap authenticate returned OK" Thu Jul 5 20:42:08 2007 : Debug: Finished request 0 state 5 Thu Jul 5 20:42:08 2007 : Debug: Going to the next request Thu Jul 5 20:42:08 2007 : Debug: Thread 1 waiting to be assigned a request Thu Jul 5 20:42:08 2007 : Debug: Waking up in 4 seconds... rad_recv: Access-Request packet from host 127.0.0.1 port 53828, id=177, length=44 Thu Jul 5 20:42:10 2007 : Debug: Thread 2 got semaphore Thu Jul 5 20:42:10 2007 : Debug: Thread 2 handling request 1, (1 handled so far) User-Name = "john" User-Password = "bad" Thu Jul 5 20:42:10 2007 : Debug: +- entering group authorize Thu Jul 5 20:42:10 2007 : Debug: modsingle[authorize]: calling files (rlm_files) for request 1 Thu Jul 5 20:42:10 2007 : Debug: users: Matched entry john at line 1 Thu Jul 5 20:42:10 2007 : Debug: modsingle[authorize]: returned from files (rlm_files) for request 1 Thu Jul 5 20:42:10 2007 : Debug: ++[files] returns ok Thu Jul 5 20:42:10 2007 : Debug: modsingle[authorize]: calling pap (rlm_pap) for request 1 Thu Jul 5 20:42:10 2007 : Debug: modsingle[authorize]: returned from pap (rlm_pap) for request 1 Thu Jul 5 20:42:10 2007 : Debug: ++[pap] returns updated Thu Jul 5 20:42:10 2007 : Debug: rad_check_password: Found Auth-Type Thu Jul 5 20:42:10 2007 : Debug: auth: type "PAP" Thu Jul 5 20:42:10 2007 : Debug: +- entering group PAP Thu Jul 5 20:42:10 2007 : Debug: ++- entering group pap-with-message Thu Jul 5 20:42:10 2007 : Debug: modsingle[authenticate]: calling pap (rlm_pap) for request 1 Thu Jul 5 20:42:10 2007 : Debug: rlm_pap: login attempt with password bad Thu Jul 5 20:42:10 2007 : Debug: rlm_pap: Using clear text password. Thu Jul 5 20:42:10 2007 : Debug: rlm_pap: Passwords don't match Thu Jul 5 20:42:10 2007 : Debug: modsingle[authenticate]: returned from pap (rlm_pap) for request 1 Thu Jul 5 20:42:10 2007 : Debug: +++[pap] returns reject Thu Jul 5 20:42:10 2007 : Debug: +++? if (ok) Thu Jul 5 20:42:10 2007 : Debug: >>> CALLING EVALUATE ok) Thu Jul 5 20:42:10 2007 : Debug: >>> LOOKING AT ok) Thu Jul 5 20:42:10 2007 : Debug: ? Evaluating "ok" -> FALSE Thu Jul 5 20:42:10 2007 : Debug: >>> I0 23:ok Thu Jul 5 20:42:10 2007 : Debug: >>> EVALUATE 1 ::):: Thu Jul 5 20:42:10 2007 : Debug: >>> AT EOL2a Thu Jul 5 20:42:10 2007 : Debug: >>> EVALUATE RETURNED ::):: Thu Jul 5 20:42:10 2007 : Debug: >>> AT EOL Thu Jul 5 20:42:10 2007 : Debug: +++? if (ok) -> FALSE Thu Jul 5 20:42:10 2007 : Debug: +++? elsif (reject) Thu Jul 5 20:42:10 2007 : Debug: >>> CALLING EVALUATE reject) Thu Jul 5 20:42:10 2007 : Debug: >>> LOOKING AT reject) Thu Jul 5 20:42:10 2007 : Debug: ? Evaluating "reject" -> TRUE Thu Jul 5 20:42:10 2007 : Debug: >>> I0 23:reject Thu Jul 5 20:42:10 2007 : Debug: >>> EVALUATE 1 ::):: Thu Jul 5 20:42:10 2007 : Debug: >>> AT EOL2a Thu Jul 5 20:42:10 2007 : Debug: >>> EVALUATE RETURNED ::):: Thu Jul 5 20:42:10 2007 : Debug: >>> AT EOL Thu Jul 5 20:42:10 2007 : Debug: +++? elsif (reject) -> TRUE Thu Jul 5 20:42:10 2007 : Debug: +++- entering elsif (reject) Thu Jul 5 20:42:10 2007 : Debug: ::: FROM 1 TO 0 MAX 1 Thu Jul 5 20:42:10 2007 : Debug: ::: Examining Reply-Message Thu Jul 5 20:42:10 2007 : Debug: ::: APPENDING Reply-Message FROM 0 TO 0 Thu Jul 5 20:42:10 2007 : Debug: ::: TO in 0 out 1 Thu Jul 5 20:42:10 2007 : Debug: ::: to[0] = Reply-Message Thu Jul 5 20:42:10 2007 : Debug: ++++[reply] returns updated Thu Jul 5 20:42:10 2007 : Debug: +++- elsif (reject) returns updated Thu Jul 5 20:42:10 2007 : Debug: ++- group pap-with-message returns reject Thu Jul 5 20:42:10 2007 : Debug: auth: Failed to validate the user. Thu Jul 5 20:42:10 2007 : Auth: Login incorrect (rlm_pap: CLEAR TEXT password check failed): [john/bad] (from client localhost port 0) Sending Access-Reject of id 177 to 127.0.0.1 port 53828 Reply-Message := "pap authenticate returned REJECT"
As you can see, the config file is still accepted. Debuglog without cumbersome workaround (elsif case only):
rad_recv: Access-Request packet from host 127.0.0.1 port 53849, id=2, length=44 Thu Jul 5 20:51:43 2007 : Debug: Thread 2 got semaphore Thu Jul 5 20:51:43 2007 : Debug: Thread 2 handling request 1, (1 handled so far) User-Name = "john" User-Password = "bad" Thu Jul 5 20:51:43 2007 : Debug: +- entering group authorize Thu Jul 5 20:51:43 2007 : Debug: modsingle[authorize]: calling files (rlm_files) for request 1 Thu Jul 5 20:51:43 2007 : Debug: users: Matched entry john at line 1 Thu Jul 5 20:51:43 2007 : Debug: modsingle[authorize]: returned from files (rlm_files) for request 1 Thu Jul 5 20:51:43 2007 : Debug: ++[files] returns ok Thu Jul 5 20:51:43 2007 : Debug: modsingle[authorize]: calling pap (rlm_pap) for request 1 Thu Jul 5 20:51:43 2007 : Debug: modsingle[authorize]: returned from pap (rlm_pap) for request 1 Thu Jul 5 20:51:43 2007 : Debug: ++[pap] returns updated Thu Jul 5 20:51:43 2007 : Debug: rad_check_password: Found Auth-Type Thu Jul 5 20:51:43 2007 : Debug: auth: type "PAP" Thu Jul 5 20:51:43 2007 : Debug: +- entering group PAP Thu Jul 5 20:51:43 2007 : Debug: ++- entering group pap-with-message Thu Jul 5 20:51:43 2007 : Debug: modsingle[authenticate]: calling pap (rlm_pap) for request 1 Thu Jul 5 20:51:43 2007 : Debug: rlm_pap: login attempt with password bad Thu Jul 5 20:51:43 2007 : Debug: rlm_pap: Using clear text password. Thu Jul 5 20:51:43 2007 : Debug: rlm_pap: Passwords don't match Thu Jul 5 20:51:43 2007 : Debug: modsingle[authenticate]: returned from pap (rlm_pap) for request 1 Thu Jul 5 20:51:43 2007 : Debug: +++[pap] returns reject Thu Jul 5 20:51:43 2007 : Debug: +++? if (ok) Thu Jul 5 20:51:43 2007 : Debug: >>> CALLING EVALUATE ok) Thu Jul 5 20:51:43 2007 : Debug: >>> LOOKING AT ok) Thu Jul 5 20:51:43 2007 : Debug: ? Evaluating "ok" -> FALSE Thu Jul 5 20:51:43 2007 : Debug: >>> I0 23:ok Thu Jul 5 20:51:43 2007 : Debug: >>> EVALUATE 1 ::):: Thu Jul 5 20:51:43 2007 : Debug: >>> AT EOL2a Thu Jul 5 20:51:43 2007 : Debug: >>> EVALUATE RETURNED ::):: Thu Jul 5 20:51:43 2007 : Debug: >>> AT EOL Thu Jul 5 20:51:43 2007 : Debug: +++? if (ok) -> FALSE Thu Jul 5 20:51:43 2007 : Debug: ++- group pap-with-message returns reject Thu Jul 5 20:51:43 2007 : Debug: auth: Failed to validate the user. Thu Jul 5 20:51:43 2007 : Auth: Login incorrect (rlm_pap: CLEAR TEXT password check failed): [john/bad] (from client localhost port 0) Sending Access-Reject of id 2 to 127.0.0.1 port 53849 Thu Jul 5 20:51:43 2007 : Debug: Finished request 1 state 5
As you can see, the elsif is not even considered. Enrik modules { pap { auto_header = yes } files { usersfile = ${confdir}/users acctusersfile = /dev/null preproxy_usersfile = /dev/null compat = no } } server { authorize { files pap } authenticate { Auth-Type PAP { group pap-with-message { # pap returns either fail or noop or ok or reject pap { # default for ok on authenticate would be to return ok = 2 # default for reject on authenticate would be to return reject = 2 } if (ok) { # the following line is the unintentional workaround # to make the elsif work reject = 2 # update returns updated with priority 1 update reply { Reply-Message := "pap authenticate returned OK" } } elsif (reject) { update reply { Reply-Message := "pap authenticate returned REJECT" } } } # override updated from above thus preserving ok/reject from pap ok = return reject = return } } } john User-Password := '{clear}secret'
Enrik Berkhan wrote:
Alan DeKok wrote:
Please check current CVS. In cases where it doesn't work, it should now print an error. This means that configurations you *think* work, but which don't really work, will now print an error.
I've re-compiled with dump_tree() enabled. From the tree dump it is obvious that I can still change the "module actions" on an if-section:
Fri Jul 6 09:14:05 2007 : Debug: if { Fri Jul 6 09:14:05 2007 : Debug: update { Fri Jul 6 09:14:05 2007 : Debug: reject = 0 Fri Jul 6 09:14:05 2007 : Debug: fail = 0 Fri Jul 6 09:14:05 2007 : Debug: ok = 0 Fri Jul 6 09:14:05 2007 : Debug: handled = 0 Fri Jul 6 09:14:05 2007 : Debug: invalid = 0 Fri Jul 6 09:14:05 2007 : Debug: userlock = 0 Fri Jul 6 09:14:05 2007 : Debug: notfound = 0 Fri Jul 6 09:14:05 2007 : Debug: noop = 0 Fri Jul 6 09:14:05 2007 : Debug: updated = 0 Fri Jul 6 09:14:05 2007 : Debug: }
The following one has been set in the config, it's not the default, no error reported though:
Fri Jul 6 09:14:05 2007 : Debug: reject = 2 Fri Jul 6 09:14:05 2007 : Debug: fail = 1 Fri Jul 6 09:14:05 2007 : Debug: ok = return Fri Jul 6 09:14:05 2007 : Debug: handled = return Fri Jul 6 09:14:05 2007 : Debug: invalid = 1 Fri Jul 6 09:14:05 2007 : Debug: userlock = return Fri Jul 6 09:14:05 2007 : Debug: notfound = return Fri Jul 6 09:14:05 2007 : Debug: noop = 1 Fri Jul 6 09:14:05 2007 : Debug: updated = 1 Fri Jul 6 09:14:05 2007 : Debug: } Fri Jul 6 09:14:05 2007 : Debug: elsif { Fri Jul 6 09:14:05 2007 : Debug: update { Fri Jul 6 09:14:05 2007 : Debug: reject = 0 Fri Jul 6 09:14:05 2007 : Debug: fail = 0 Fri Jul 6 09:14:05 2007 : Debug: ok = 0 Fri Jul 6 09:14:05 2007 : Debug: handled = 0 Fri Jul 6 09:14:05 2007 : Debug: invalid = 0 Fri Jul 6 09:14:05 2007 : Debug: userlock = 0 Fri Jul 6 09:14:05 2007 : Debug: notfound = 0 Fri Jul 6 09:14:05 2007 : Debug: noop = 0 Fri Jul 6 09:14:05 2007 : Debug: updated = 0 Fri Jul 6 09:14:05 2007 : Debug: } Fri Jul 6 09:14:05 2007 : Debug: reject = return Fri Jul 6 09:14:05 2007 : Debug: fail = 1 Fri Jul 6 09:14:05 2007 : Debug: ok = return Fri Jul 6 09:14:05 2007 : Debug: handled = return Fri Jul 6 09:14:05 2007 : Debug: invalid = 1 Fri Jul 6 09:14:05 2007 : Debug: userlock = return Fri Jul 6 09:14:05 2007 : Debug: notfound = return Fri Jul 6 09:14:05 2007 : Debug: noop = 1 Fri Jul 6 09:14:05 2007 : Debug: updated = 1 Fri Jul 6 09:14:05 2007 : Debug: }
What about enabling dump_tree() by default but only dump the tree at debug level, say, 5? Enrik
Enrik Berkhan wrote:
I've re-compiled with dump_tree() enabled. From the tree dump it is obvious that I can still change the "module actions" on an if-section:
Hmm... the code is weirder than I thought. My tests found cases where "ok=1" didn't work, so it now complains in those cases. Your config not only parses, but works.
What about enabling dump_tree() by default but only dump the tree at debug level, say, 5?
I don't see a need for it. The only time the contents of the tree matter is when we're debugging the parser and/or the interpretor. That hasn't been necessary for the past 6 years. It's only necessary now because new features are being added. Once the features are stable, dump_tree() isn't necessary. Alan DeKok.
Enrik Berkhan wrote: ...
Debuglog without cumbersome workaround (elsif case only): ...
Thu Jul 5 20:51:43 2007 : Debug: +++? if (ok) -> FALSE Thu Jul 5 20:51:43 2007 : Debug: ++- group pap-with-message returns reject
Because the default action for "reject" in "authenticate" sections is to return. You have to over-ride it via "pap {}" for the "if" to even be considered.
As you can see, the elsif is not even considered.
Yes. The solution, I think, is to *not* put logic into the "authenticate" section. As I said before, put it in "post-auth", where it belongs. Alan DeKok.
Hi, Alan DeKok wrote:
Yes. The solution, I think, is to *not* put logic into the "authenticate" section.
As I said before, put it in "post-auth", where it belongs.
Another artificial example that might surprise the novice unlang user:
modules {
always always-ok { rcode = ok } always always-reject { rcode = reject }
}
server {
authorize {
# reject, but continue always-reject { reject = 1 }
if (ok) { update reply { Reply-Message := '%{User-Name:-unknown} authorized!' } always-ok } elsif (reject) { update reply { Reply-Message := "Go away, %{User-Name:-unknown}!" } always-reject }
}
}
Here, again, the elsif will never be considered. Really, it's an unlang ... :) Enrik
Enrik Berkhan wrote:
Another artificial example that might surprise the novice unlang user:
It's not that artificial. 1) "update" sections should change the return code only when something goes wrong -> fix has been committed 2) "else" / "elsif" sections should NOT change the return code when they are not taken -> fix has been committed. Please try it again. You should not need the "always-ok" in the "if (ok)" block, or the "always-reject" in the "if (reject)" block. Alan DeKok.
Alan DeKok schrieb:
Please try it again. You should not need the "always-ok" in the "if (ok)" block, or the "always-reject" in the "if (reject)" block.
Yes, now both examples work like "expected". Working authorize example:
modules {
always always-reject { rcode = reject }
}
server {
authorize {
# reject, but continue always-reject { reject = 1 }
if (ok) { update reply { Reply-Message := 'Hi, there!' } } elsif (reject) { update reply { Reply-Message := "Go away, %{User-Name:-unknown}!" } }
}
}
The elsif is taken always, as it should, and reject will be returned without further action. Of course, the if can't be tested in this setup. Working authenticate example, even if you don't like it :)
modules {
pap { auto_header = yes }
files { usersfile = ${confdir}/users acctusersfile = /dev/null preproxy_usersfile = /dev/null compat = no }
}
server {
authorize { files pap }
authenticate { Auth-Type PAP { # pap returns either fail or noop or ok or reject pap { # default for ok on authenticate would be to return ok = 1 # default for reject on authenticate would be to return reject = 1 } if (ok) { update reply { Reply-Message := "pap authenticate returned OK" } } elsif (reject) { update reply { Reply-Message := "pap authenticate returned REJECT" } } } }
Here, the if is taken if user/password is correct and ok will be propagated by the if block. The elsif is taken if the user is authorized but uses a wrong password and reject will be propagated by the elsif block. The reply is updated in both cases as expected. Thanks for the fix! Enrik
participants (3)
-
Alan DeKok -
Arran Cudbard-Bell -
Enrik Berkhan