Added "return" keyword
authorAlan T. DeKok <aland@freeradius.org>
Tue, 28 Oct 2014 13:35:26 +0000 (09:35 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 28 Oct 2014 13:35:26 +0000 (09:35 -0400)
man/man5/unlang.5
src/main/modcall.c
src/tests/keywords/return

index 3fb0cac..53d70a1 100644 (file)
@@ -10,7 +10,7 @@
 .RE
 .sp
 ..
-.TH unlang 5 "15 April 2014" "" "FreeRADIUS Processing un-language"
+.TH unlang 5 "28 October 2014" "" "FreeRADIUS Processing un-language"
 .SH NAME
 unlang \- FreeRADIUS Processing un\-language
 .SH DESCRIPTION
@@ -293,6 +293,30 @@ or update an attribute list.
 .br
        }
 .DE
+
+.IP return
+.br
+Returns from the current top-level section, e.g. "authorize" or
+"authenticate".  This keyword is mainly used to avoid layers of nested
+"if" and "else" statements.
+
+.DS
+       authorize {
+.br
+               if (...) {
+.br
+                       ...
+.br
+                       return
+.br
+               }
+.br
+               ...  # this is never reached when the "if"
+.br
+               ...  # statement is executed
+.br
+       }
+.DE
 .SH ATTRIBUTE REFERENCES
 
 Attributes may be referenced via the following syntax:
index 1b18a85..61714ec 100644 (file)
@@ -52,7 +52,7 @@ struct modcallable {
        enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
 #ifdef WITH_UNLANG
               MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
-              MOD_FOREACH, MOD_BREAK,
+              MOD_FOREACH, MOD_BREAK, MOD_RETURN,
 #endif
               MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
        rlm_components_t method;
@@ -362,6 +362,7 @@ static char const *group_name[] = {
        "case",
        "foreach",
        "break",
+       "return",
 #endif
        "policy",
        "reference",
@@ -691,13 +692,18 @@ redo:
                        }
 
                        /*
-                        *      If we've been told to stop processing
-                        *      it, do so.
+                        *      We've unwound to the enclosing
+                        *      "foreach".  Stop the unwinding.
                         */
                        if (entry->unwind == MOD_FOREACH) {
                                entry->unwind = 0;
                                break;
                        }
+
+                       /*
+                        *      Unwind all the way.
+                        */
+                       if (entry->unwind == MOD_RETURN) break;
                } /* loop over VPs */
 
                /*
@@ -736,7 +742,19 @@ redo:
                entry->unwind = MOD_FOREACH;
                goto finish;
        } /* MOD_BREAK */
-#endif   /* WITH_PROXY */
+
+       /*
+        *      Stop processing the current section, no matter how
+        *      deeply the current processing is.
+        */
+       if (c->type == MOD_RETURN) {
+               /*
+                *      Leave result / priority on the stack, and stop processing the section.
+                */
+               entry->unwind = MOD_RETURN;
+               goto finish;
+       } /* MOD_BREAK */
+#endif   /* WITH_UNLANG */
 
        /*
         *      Child is a group that has children of it's own.
@@ -1066,12 +1084,14 @@ calculate_result:
         *      If we've been told to stop processing
         *      it, do so.
         */
-       if (entry->unwind != 0) {
+       if (entry->unwind == MOD_FOREACH) {
                RDEBUG2("# unwind to enclosing %s", group_name[entry->unwind]);
                entry->unwind = 0;
                goto finish;
        }
 
+       if (entry->unwind == MOD_RETURN) goto finish;
+
 next_sibling:
        entry->c = entry->c->next;
 
@@ -2478,6 +2498,12 @@ static modcallable *do_compile_modsingle(modcallable *parent,
        if (strcmp(modrefname, "break") == 0) {
                return do_compile_modbreak(parent, component, ci);
        }
+
+       if (strcmp(modrefname, "return") == 0) {
+               return do_compile_modgroup(parent, component, NULL,
+                                          GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
+                                          MOD_RETURN);
+       }
 #endif
 
        /*
@@ -2703,7 +2729,7 @@ static modcallable *do_compile_modgroup(modcallable *parent,
        c->next = NULL;
        memset(c->actions, 0, sizeof(c->actions));
 
-       if (!cs) {              /* only for "break" */
+       if (!cs) {              /* only for "break" and "return" */
                c->name = "";
                goto set_codes;
        }
@@ -3367,8 +3393,9 @@ bool modcall_pass2(modcallable *mc)
                        break;
 
                case MOD_XLAT:   /* @todo: pre-parse xlat's */
-               case MOD_BREAK:
                case MOD_REFERENCE:
+               case MOD_BREAK:
+               case MOD_RETURN:
 #endif
 
                case MOD_SINGLE:
index f79ef02..49779a5 100644 (file)
@@ -1,13 +1,33 @@
-update {
-       control:Auth-Type = 'Accept'
-       reply:Reply-Message = 'pass'
+#
+#  PRE: update if
+#
+update control {
+       Cleartext-Password := 'hello'
 }
 
-# Section should exit after this statement
-ok {
-       ok = return
-}
+if (User-Name == "bob") {
+       update reply {
+               Filter-Id := "filter"
+       }
+
+       #
+       #  We need this because the "return" below
+       #  will prevent the "pap" module from being run
+       #  in the "authorize" section.
+       #
+       update control {
+               Auth-Type := PAP
+       }
+
+       #
+       #  Stop processing "authorize", and go to the next section.
+       #
+       return
 
-update {
-       reply:Reply-Message := 'fail'
+       #
+       #  Shouldn't reach this
+       #
+       update reply {
+               Filter-Id := "fail"
+       }
 }