<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    On 24/09/2013 13:10, Jakob Hirsch wrote:
    <br>
    <blockquote type="cite" style="color: #000000;">Hi,
      <br>
      <br>
      another issue in 2.2.1 (and the current v2.x.x git): if-blocks in
      an
      <br>
      authenticate section cause to wrong rejects.
      <br>
      <br>
      Example with minimal config:
      <br>
      <br>
      authorize {
      <br>
           update control {
      <br>
               Auth-Type := 'Test'
      <br>
           }
      <br>
      }
      <br>
      <br>
      authenticate {
      <br>
               if (1) {
      <br>
                   #noop
      <br>
                   #update reply {
      <br>
                   #    Reply-Message := "bla"
      <br>
                   #}
      <br>
               }
      <br>
               ok
      <br>
           }
      <br>
      }
      <br>
    </blockquote>
    I queried this a while ago, and it seems to be intentional (albeit
    sparsely documented) behaviour.
    <br>
    <br>
    Configurable failover is described here:
    <br>
    <a class="moz-txt-link-freetext"
      href="http://wiki.freeradius.org/config/Fail-over">http://wiki.freeradius.org/config/Fail-over</a>
    <br>
    <br>
    A sequence of modules like
    <br>
    <br>
        foo
    <br>
        bar
    <br>
        baz
    <br>
    <br>
    is a group, and if one of those modules gives a failure status, the
    entire group terminates early unless you've applied a numeric value
    to the failure code, in which case it will be carried forward.
    <br>
    <br>
    Now, an 'if' block is itself a failover block. So if there was a
    success or fail status set before the start of the block, it will
    cause the whole group within which the 'if' is enclosed to terminate
    at the end of that block - even if the 'if' block itself did nothing
    to set success or fail status. But this doesn't happen if the block
    is skipped because the condition was false.
    <br>
    <br>
    Here's an example. I want to conditionally log CHAP failures, and I
    also want to call additional code in policy.conf (e.g. to turn some
    access-rejects into access-accept with a walled garden).
    <br>
    <br>
    The config looks something like this:
    <br>
    <br>
    <tt>authenticate {
    </tt><tt><br>
    </tt><tt>        Auth-Type CHAP {
    </tt><tt><br>
    </tt><tt>                chap {
    </tt><tt><br>
    </tt><tt>                        ok = return
    </tt><tt><br>
    </tt><tt>                        reject = 1
    </tt><tt><br>
    </tt><tt>                }
    </tt><tt><br>
    </tt><tt>
    </tt><tt><br>
    </tt><tt>                if (some condition) {
    </tt><tt><br>
    </tt><tt>                        update control {
    </tt><tt><br>
    </tt><tt>                                Tmp-String-0 += "CHAP
      %{%{request:CHAP-Challenge}:-%{request:Packet-Authentication-Vector}}
      %{request:CHAP-Password}"
    </tt><tt><br>
    </tt><tt>                        }
    </tt><tt><br>
    </tt><tt>                        # 'if' is an instance of
      configurable failover;
    </tt><tt><br>
    </tt><tt>                        # we must prevent an early return
    </tt><tt><br>
    </tt><tt>                        reject = 1
    </tt><tt><br>
    </tt><tt>                }
    </tt><tt><br>
    </tt><tt>
    </tt><tt><br>
    </tt><tt>                handleReject
    </tt><tt><br>
    </tt><tt>        }
    </tt><tt><br>
    </tt><tt>}
    </tt><br>
    <br>
    If the second "reject = 1" is omitted, then termination occurs at
    the end of the 'if' block, before handleReject is called.
    <br>
    <br>
    Now, handleReject is defined in policy.conf. Suppose I want to
    update an attribute conditionally in there. This also has the same
    issue:
    <br>
    <br>
    <tt>policy {
    </tt><tt><br>
    </tt><tt>        handleReject {
    </tt><tt><br>
    </tt><tt>            if (some condition) {
    </tt><tt><br>
    </tt><tt>                update control {
    </tt><tt><br>
    </tt><tt>                    SomeAttr := "somevalue"
    </tt><tt><br>
    </tt><tt>                }
    </tt><tt><br>
    </tt><tt>                # Behaviour of configurable failover: a
      reject set
    </tt><tt><br>
    </tt><tt>                # earlier causes an implicit 'return' at
      the end of an 'if'.
    </tt><tt><br>
    </tt><tt>                # We need this line to prevent it.
    </tt><tt><br>
    </tt><tt>                reject = 1
    </tt><tt><br>
    </tt><tt>            }
    </tt><tt><br>
    </tt><tt>            ... continue
    </tt><tt><br>
    </tt><tt>        }
    </tt><tt><br>
    </tt><tt>}
    </tt><br>
    <br>
    <br>
    Furthermore, if handleReject decides to do nothing, but you want to
    continue after handleReject to another module in the authenticate {}
    block, it also needs to end with a 'reject = 1'
    <br>
    <br>
    <tt>authenticate {
    </tt><tt><br>
    </tt><tt>        Auth-Type CHAP {
    </tt><tt><br>
    </tt><tt>...
    </tt><tt><br>
    </tt><tt>                handleReject
    </tt><tt><br>
    </tt><tt>                doSomethingElse
    </tt><tt><br>
    </tt><tt>        }
    </tt><tt><br>
    </tt><tt>}
    </tt><tt><br>
    </tt><tt>
    </tt><tt><br>
    </tt><tt>policy {
    </tt><tt><br>
    </tt><tt>    handleReject {
    </tt><tt><br>
    </tt><tt>        ...
    </tt><tt><br>
    </tt><tt>        reject = 1
    </tt><tt><br>
    </tt><tt>    }
    </tt><tt><br>
    </tt><tt>}
    </tt><tt><br>
    </tt><tt>
    </tt><br>
    In this case, it has to be put at the end of the block definition in
    policy.conf, not at the point where it is invoked. What I expected
    (but is <b class="moz-txt-star"><span class="moz-txt-tag">*</span>not<span
        class="moz-txt-tag">*</span></b> the case) was:
    <br>
    <br>
    <tt>authenticate {
    </tt><tt><br>
    </tt><tt>        Auth-Type CHAP {
    </tt><tt><br>
    </tt><tt>...
    </tt><tt><br>
    </tt><tt>                handleReject {
    </tt><tt><br>
    </tt><tt>                    reject = 1   # CAN'T BE APPLIED HERE
    </tt><tt><br>
    </tt><tt>                }
    </tt><tt><br>
    </tt><tt>                doSomethingElse
    </tt><tt><br>
    </tt><tt>        }
    </tt><tt><br>
    </tt><tt>}
    </tt><br>
    <br>
    I wonder if this could all be made to work in a more intuitive way -
    for example, once a module has set "reject = 1" this status sticks
    until another 'real' module is called, as opposed to just update {
    ... } sections.
    <br>
    <br>
    Anyway, this is just something I've had to grit my teeth and bear
    with. It seems really weird, but eventually makes sort of sense. I
    ended up having to write a test suite (invoking radclient with all
    the different cases) to make sure they all worked the way I wanted.
    <br>
    <br>
    Regards,
    <br>
    <br>
    Brian.
    <br>
    <br>
    P.S. In some cases there may be multiple return conditions you need
    to tag:
    <br>
    <br>
    <tt>        Auth-Type PAP {
    </tt><tt><br>
    </tt><tt>                pap {
    </tt><tt><br>
    </tt><tt>                        ok = return
    </tt><tt><br>
    </tt><tt>                        reject = 1      # password mismatch
    </tt><tt><br>
    </tt><tt>                        fail = 1        # no password to
      match in control list
    </tt><tt><br>
    </tt><tt>                        invalid = 1     # no password in
      request
    </tt><tt><br>
    </tt><tt>                }
    </tt><tt><br>
    </tt><tt>                ... continue
    </tt><br>
    <br>
    In practice, if you use the 'pap' module in the authorize section,
    it won't set Auth-Type := PAP unless there is a User-Password in the
    request.
    <br>
  </body>
</html>