.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
.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:
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;
"case",
"foreach",
"break",
+ "return",
#endif
"policy",
"reference",
}
/*
- * 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 */
/*
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.
* 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;
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
/*
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;
}
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:
-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"
+ }
}