6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000,2006 The FreeRADIUS server project
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/modpriv.h>
27 #include <freeradius-devel/modcall.h>
28 #include <freeradius-devel/parser.h>
29 #include <freeradius-devel/rad_assert.h>
32 /* mutually-recursive static functions need a prototype up front */
33 static modcallable *do_compile_modgroup(modcallable *,
34 rlm_components_t, CONF_SECTION *,
37 /* Actions may be a positive integer (the highest one returned in the group
38 * will be returned), or the keyword "return", represented here by
39 * MOD_ACTION_RETURN, to cause an immediate return.
40 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
41 * to cause an immediate reject. */
42 #define MOD_ACTION_RETURN (-1)
43 #define MOD_ACTION_REJECT (-2)
45 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
46 * explanation of what they are all about, see doc/configurable_failover.rst */
49 struct modcallable *next;
51 enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
53 MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
54 MOD_FOREACH, MOD_BREAK,
56 MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
57 rlm_components_t method;
58 int actions[RLM_MODULE_NUMCODES];
61 #define MOD_LOG_OPEN_BRACE(_name) RDEBUG2("%.*s%s %s {", depth + 1, modcall_spaces, _name ? _name : "", c->name)
62 #define MOD_LOG_CLOSE_BRACE() RDEBUG2("%.*s} # %s %s = %s", depth + 1, modcall_spaces, \
63 cf_section_name1(g->cs) ? cf_section_name1(g->cs) : "", c->name ? c->name : "", \
64 fr_int2str(mod_rcode_table, result, "<invalid>"))
67 modcallable mc; /* self */
73 } grouptype; /* after mc */
74 modcallable *children;
75 modcallable *tail; /* of the children list */
77 value_pair_map_t *map; /* update */
78 value_pair_tmpl_t *vpt; /* switch */
79 fr_cond_t *cond; /* if/elsif */
85 module_instance_t *modinst;
101 static const FR_NAME_NUMBER grouptype_table[] = {
102 { "", GROUPTYPE_SIMPLE },
103 { "redundant ", GROUPTYPE_REDUNDANT },
104 { "append ", GROUPTYPE_APPEND },
109 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
110 * so we often want to go back and forth between them. */
111 static modsingle *mod_callabletosingle(modcallable *p)
113 rad_assert(p->type==MOD_SINGLE);
114 return (modsingle *)p;
116 static modgroup *mod_callabletogroup(modcallable *p)
118 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
120 return (modgroup *)p;
122 static modcallable *mod_singletocallable(modsingle *p)
124 return (modcallable *)p;
126 static modcallable *mod_grouptocallable(modgroup *p)
128 return (modcallable *)p;
131 static modref *mod_callabletoref(modcallable *p)
133 rad_assert(p->type==MOD_REFERENCE);
136 static modcallable *mod_reftocallable(modref *p)
138 return (modcallable *)p;
141 static modxlat *mod_callabletoxlat(modcallable *p)
143 rad_assert(p->type==MOD_XLAT);
146 static modcallable *mod_xlattocallable(modxlat *p)
148 return (modcallable *)p;
151 /* modgroups are grown by adding a modcallable to the end */
152 static void add_child(modgroup *g, modcallable *c)
157 g->children = g->tail = c;
159 rad_assert(g->tail->next == NULL);
164 c->parent = mod_grouptocallable(g);
167 /* Here's where we recognize all of our keywords: first the rcodes, then the
169 const FR_NAME_NUMBER mod_rcode_table[] = {
170 { "reject", RLM_MODULE_REJECT },
171 { "fail", RLM_MODULE_FAIL },
172 { "ok", RLM_MODULE_OK },
173 { "handled", RLM_MODULE_HANDLED },
174 { "invalid", RLM_MODULE_INVALID },
175 { "userlock", RLM_MODULE_USERLOCK },
176 { "notfound", RLM_MODULE_NOTFOUND },
177 { "noop", RLM_MODULE_NOOP },
178 { "updated", RLM_MODULE_UPDATED },
184 * Compile action && rcode for later use.
186 static int compile_action(modcallable *c, CONF_PAIR *cp)
189 char const *attr, *value;
191 attr = cf_pair_attr(cp);
192 value = cf_pair_value(cp);
193 if (!value) return 0;
195 if (!strcasecmp(value, "return"))
196 action = MOD_ACTION_RETURN;
198 else if (!strcasecmp(value, "break"))
199 action = MOD_ACTION_RETURN;
201 else if (!strcasecmp(value, "reject"))
202 action = MOD_ACTION_REJECT;
204 else if (strspn(value, "0123456789")==strlen(value)) {
205 action = atoi(value);
208 * Don't allow priority zero, for future use.
210 if (action == 0) return 0;
212 cf_log_err_cp(cp, "Unknown action '%s'.\n",
217 if (strcasecmp(attr, "default") != 0) {
220 rcode = fr_str2int(mod_rcode_table, attr, -1);
223 "Unknown module rcode '%s'.\n",
227 c->actions[rcode] = action;
229 } else { /* set all unset values to the default */
232 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
233 if (!c->actions[i]) c->actions[i] = action;
240 /* Some short names for debugging output */
241 static char const * const comp2str[] = {
257 #ifdef HAVE_PTHREAD_H
259 * Lock the mutex for the module
261 static void safe_lock(module_instance_t *instance)
264 pthread_mutex_lock(instance->mutex);
268 * Unlock the mutex for the module
270 static void safe_unlock(module_instance_t *instance)
273 pthread_mutex_unlock(instance->mutex);
277 * No threads: these functions become NULL's.
279 #define safe_lock(foo)
280 #define safe_unlock(foo)
283 static rlm_rcode_t CC_HINT(nonnull) call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
288 * If the request should stop, refuse to do anything.
290 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
291 if (blocked) return RLM_MODULE_NOOP;
294 RDEBUG3("modsingle[%s]: calling %s (%s) for request %d",
295 comp2str[component], sp->modinst->name,
296 sp->modinst->entry->name, request->number);
298 if (sp->modinst->force) {
299 request->rcode = sp->modinst->code;
303 safe_lock(sp->modinst);
306 * For logging unresponsive children.
308 request->module = sp->modinst->name;
310 request->rcode = sp->modinst->entry->module->methods[component](sp->modinst->insthandle, request);
312 request->module = "";
313 safe_unlock(sp->modinst);
316 * Wasn't blocked, and now is. Complain!
318 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
320 RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
325 RDEBUG3("modsingle[%s]: returned from %s (%s) for request %d",
326 comp2str[component], sp->modinst->name,
327 sp->modinst->entry->name, request->number);
329 return request->rcode;
332 static int default_component_results[RLM_COMPONENT_COUNT] = {
333 RLM_MODULE_REJECT, /* AUTH */
334 RLM_MODULE_NOTFOUND, /* AUTZ */
335 RLM_MODULE_NOOP, /* PREACCT */
336 RLM_MODULE_NOOP, /* ACCT */
337 RLM_MODULE_FAIL, /* SESS */
338 RLM_MODULE_NOOP, /* PRE_PROXY */
339 RLM_MODULE_NOOP, /* POST_PROXY */
340 RLM_MODULE_NOOP /* POST_AUTH */
343 RLM_MODULE_NOOP, /* RECV_COA_TYPE */
344 RLM_MODULE_NOOP /* SEND_COA_TYPE */
349 static char const *group_name[] = {
353 "load-balance group",
354 "redundant-load-balance group",
370 static char const *modcall_spaces = " ";
372 #define MODCALL_STACK_MAX (32)
375 * Don't call the modules recursively. Instead, do them
376 * iteratively, and manage the call stack ourselves.
378 typedef struct modcall_stack_entry_t {
381 int unwind; /* unwind to this one if it exists */
383 } modcall_stack_entry_t;
386 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
387 modcall_stack_entry_t *entry);
390 * Call a child of a block.
392 static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
393 modcall_stack_entry_t *entry, modcallable *c,
396 modcall_stack_entry_t *next;
398 if (depth >= MODCALL_STACK_MAX) {
399 ERROR("Internal sanity check failed: module stack is too deep");
404 * Initialize the childs stack frame.
408 next->result = entry->result;
412 if (!modcall_recurse(request, component,
414 *result = RLM_MODULE_FAIL;
419 * Unwind back up the stack
421 if (next->unwind != 0) {
422 entry->unwind = next->unwind;
425 *result = next->result;
431 * Interpret the various types of blocks.
433 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
434 modcall_stack_entry_t *entry)
436 bool if_taken, was_if;
441 was_if = if_taken = false;
442 result = RLM_MODULE_UNKNOWN;
449 * Nothing more to do. Return the code and priority
450 * which was set by the caller.
455 * We've been asked to stop. Do so.
457 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
459 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
460 entry->result = RLM_MODULE_FAIL;
461 entry->priority = 9999;
467 * Handle "if" conditions.
469 if (c->type == MOD_IF) {
474 g = mod_callabletogroup(c);
475 rad_assert(g->cond != NULL);
477 RDEBUG2("%.*s %s %s", depth + 1, modcall_spaces,
478 group_name[c->type], c->name);
480 condition = radius_evaluate_cond(request, result, 0, g->cond);
483 REDEBUG("Failed retrieving values required to evaluate condition");
485 RDEBUG2("%.*s %s %s -> %s", depth + 1, modcall_spaces,
487 c->name, condition ? "TRUE" : "FALSE");
491 * Didn't pass. Remember that.
500 * We took the "if". Go recurse into its' children.
508 * "else" if the previous "if" was taken.
509 * "if" if the previous if wasn't taken.
511 if (c->type == MOD_ELSIF) {
512 if (!was_if) goto elsif_error;
515 * Like MOD_ELSE, but allow for a later "else"
518 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
519 depth + 1, modcall_spaces,
520 group_name[c->type], request->number);
527 * Check the "if" condition.
533 * "else" for a preceding "if".
535 if (c->type == MOD_ELSE) {
536 if (!was_if) { /* error */
538 RDEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
539 depth + 1, modcall_spaces,
540 group_name[c->type], request->number);
545 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
546 depth + 1, modcall_spaces,
547 group_name[c->type], request->number);
554 * We need to process it. Go do that.
562 * We're no longer processing if/else/elsif. Reset the
563 * trackers for those conditions.
567 #endif /* WITH_UNLANG */
569 if (c->type == MOD_SINGLE) {
573 * Process a stand-alone child, and fall through
574 * to dealing with it's parent.
576 sp = mod_callabletosingle(c);
578 result = call_modsingle(c->method, sp, request);
579 RDEBUG2("%.*s[%s] = %s", depth + 1, modcall_spaces, c->name ? c->name : "",
580 fr_int2str(mod_rcode_table, result, "<invalid>"));
581 goto calculate_result;
586 * Update attribute(s)
588 if (c->type == MOD_UPDATE) {
590 modgroup *g = mod_callabletogroup(c);
591 value_pair_map_t *map;
594 MOD_LOG_OPEN_BRACE("update");
595 for (map = g->map; map != NULL; map = map->next) {
596 rcode = radius_map2request(request, map, radius_map2vp, NULL);
598 result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
599 MOD_LOG_CLOSE_BRACE();
600 goto calculate_result;
604 result = RLM_MODULE_NOOP;
605 MOD_LOG_CLOSE_BRACE();
606 goto calculate_result;
610 * Loop over a set of attributes.
612 if (c->type == MOD_FOREACH) {
613 int i, foreach_depth = -1;
614 VALUE_PAIR *vps, *vp;
615 modcall_stack_entry_t *next = NULL;
616 vp_cursor_t cursor, copy;
617 modgroup *g = mod_callabletogroup(c);
619 if (depth >= MODCALL_STACK_MAX) {
620 ERROR("Internal sanity check failed: module stack is too deep");
625 * Figure out how deep we are in nesting by looking at request_data
628 for (i = 0; i < 8; i++) {
629 if (!request_data_reference(request,
636 if (foreach_depth < 0) {
637 REDEBUG("foreach Nesting too deep!");
638 result = RLM_MODULE_FAIL;
639 goto calculate_result;
642 if (radius_tmpl_get_vp(&vp, request, g->vpt) < 0) { /* nothing to loop over */
643 MOD_LOG_OPEN_BRACE("foreach");
644 result = RLM_MODULE_NOOP;
645 MOD_LOG_CLOSE_BRACE();
646 goto calculate_result;
650 * Copy the VPs from the original request, this ensures deterministic
651 * behaviour if someone decides to add or remove VPs in the set were
656 fr_cursor_init(&cursor, &vp);
658 /* Prime the cursor. */
659 cursor.found = cursor.current;
660 for (fr_cursor_init(©, &vps);
662 vp = fr_cursor_next_by_da(&cursor, vp->da, g->vpt->attribute.tag)) {
665 MEM(tmp = paircopyvp(request, vp));
666 fr_cursor_insert(©, tmp);
669 RDEBUG2("%.*sforeach %s ", depth + 1, modcall_spaces, c->name);
671 rad_assert(vps != NULL);
674 * This is the actual body of the foreach loop
676 for (vp = fr_cursor_first(©);
678 vp = fr_cursor_next(©)) {
680 if (fr_debug_flag >= 2) {
683 vp_prints_value(buffer, sizeof(buffer), vp, '"');
684 RDEBUG2("%.*s # Foreach-Variable-%d = %s", depth + 1,
685 modcall_spaces, foreach_depth, buffer);
690 * Add the vp to the request, so that
691 * xlat.c, xlat_foreach() can find it.
693 request_data_add(request, radius_get_vp, foreach_depth, &vp, false);
696 * Initialize the childs stack frame.
699 next->c = g->children;
700 next->result = entry->result;
704 if (!modcall_recurse(request, component, depth + 1, next)) {
709 * If we've been told to stop processing
712 if (entry->unwind == MOD_FOREACH) {
716 } /* loop over VPs */
720 rad_assert(next != NULL);
721 result = next->result;
722 priority = next->priority;
723 MOD_LOG_CLOSE_BRACE();
724 goto calculate_result;
728 * Break out of a "foreach" loop.
730 if (c->type == MOD_BREAK) {
734 for (i = 8; i >= 0; i--) {
735 copy_p = request_data_get(request, radius_get_vp, i);
737 RDEBUG2("%.*s # break Foreach-Variable-%d", depth + 1, modcall_spaces, i);
743 * Leave result / priority on the stack, and stop processing the section.
745 entry->unwind = MOD_FOREACH;
748 #endif /* WITH_PROXY */
751 * Child is a group that has children of it's own.
753 if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
755 || (c->type == MOD_CASE)
763 g = mod_callabletogroup(c);
766 * This should really have been caught in the
767 * compiler, and the node never generated. But
768 * doing that requires changing it's API so that
769 * it returns a flag instead of the compiled
773 RDEBUG2("%.*s%s { ... } # empty sub-section is ignored",
774 depth + 1, modcall_spaces, c->name);
779 MOD_LOG_OPEN_BRACE(cf_section_name1(g->cs));
781 RDEBUG2("%.*s%s {", depth + 1, modcall_spaces, cf_section_name1(g->cs));
783 modcall_child(request, component,
784 depth + 1, entry, g->children,
786 MOD_LOG_CLOSE_BRACE();
787 goto calculate_result;
791 if (c->type == MOD_SWITCH) {
792 modcallable *this, *found, *null_case;
795 value_pair_map_t map;
797 MOD_LOG_OPEN_BRACE("switch");
799 g = mod_callabletogroup(c);
801 memset(&cond, 0, sizeof(cond));
802 memset(&map, 0, sizeof(map));
804 cond.type = COND_TYPE_MAP;
805 cond.data.map = ↦
807 map.op = T_OP_CMP_EQ;
808 map.ci = cf_sectiontoitem(g->cs);
810 rad_assert(g->vpt != NULL);
812 null_case = found = NULL;
815 * The attribute doesn't exist. We can skip
816 * directly to the default 'case' statement.
818 if ((g->vpt->type == VPT_TYPE_ATTR) && (radius_tmpl_get_vp(NULL, request, g->vpt) < 0)) {
819 for (this = g->children; this; this = this->next) {
820 rad_assert(this->type == MOD_CASE);
822 h = mod_callabletogroup(this);
823 if (h->vpt) continue;
833 * Find either the exact matching name, or the
834 * "case {...}" statement.
836 for (this = g->children; this; this = this->next) {
837 rad_assert(this->type == MOD_CASE);
839 h = mod_callabletogroup(this);
842 * Remember the default case
845 if (!null_case) null_case = this;
850 * If we're switching over an attribute
851 * AND we haven't pre-parsed the data for
852 * the case statement, then cast the data
853 * to the type of the attribute.
855 if ((g->vpt->type == VPT_TYPE_ATTR) &&
856 (h->vpt->type != VPT_TYPE_DATA)) {
859 cond.cast = g->vpt->vpt_da;
862 * Remove unnecessary casting.
864 if ((h->vpt->type == VPT_TYPE_ATTR) &&
865 (g->vpt->vpt_da->type == h->vpt->vpt_da->type)) {
874 if (radius_evaluate_map(request, RLM_MODULE_UNKNOWN, 0,
881 if (!found) found = null_case;
884 modcall_child(request, component,
885 depth + 1, entry, found,
887 MOD_LOG_CLOSE_BRACE();
888 goto calculate_result;
892 if ((c->type == MOD_LOAD_BALANCE) ||
893 (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
895 modcallable *this, *found;
898 MOD_LOG_OPEN_BRACE("load-balance");
900 g = mod_callabletogroup(c);
902 for (this = g->children; this; this = this->next) {
910 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
915 MOD_LOG_OPEN_BRACE(group_name[c->type]);
917 if (c->type == MOD_LOAD_BALANCE) {
918 modcall_child(request, component,
919 depth + 1, entry, found,
926 * Loop over all children in this
927 * section. If we get FAIL, then
928 * continue. Otherwise, stop.
930 for (i = 1; i < count; i++) {
931 modcall_child(request, component,
932 depth + 1, entry, found,
934 if (c->actions[result] == MOD_ACTION_RETURN) {
940 MOD_LOG_CLOSE_BRACE();
941 goto calculate_result;
942 } /* MOD_LOAD_BALANCE */
945 * Reference another virtual server.
947 * This should really be deleted, and replaced with a
948 * more abstracted / functional version.
950 if (c->type == MOD_REFERENCE) {
951 modref *mr = mod_callabletoref(c);
952 char const *server = request->server;
954 if (server == mr->ref_name) {
955 RWDEBUG("Suppressing recursive call to server %s", server);
959 request->server = mr->ref_name;
960 RDEBUG("server %s { # nested call", mr->ref_name);
961 result = indexed_modcall(component, 0, request);
962 RDEBUG("} # server %s with nested call", mr->ref_name);
963 request->server = server;
964 goto calculate_result;
965 } /* MOD_REFERENCE */
968 * xlat a string without doing anything else
970 * This should really be deleted, and replaced with a
971 * more abstracted / functional version.
973 if (c->type == MOD_XLAT) {
974 modxlat *mx = mod_callabletoxlat(c);
978 radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
980 RDEBUG("`%s`", mx->xlat_name);
981 radius_exec_program(request, mx->xlat_name, false, true, NULL, 0,
982 EXEC_TIMEOUT, request->packet->vps, NULL);
989 * Add new module types here.
994 RDEBUG("(%s, %d) ? (%s, %d)",
995 fr_int2str(mod_rcode_table, result, "<invalid>"),
997 fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
1002 rad_assert(result != RLM_MODULE_UNKNOWN);
1005 * The child's action says return. Do so.
1007 if ((c->actions[result] == MOD_ACTION_RETURN) &&
1009 entry->result = result;
1014 * If "reject", break out of the loop and return
1017 if (c->actions[result] == MOD_ACTION_REJECT) {
1018 entry->result = RLM_MODULE_REJECT;
1023 * The array holds a default priority for this return
1024 * code. Grab it in preference to any unset priority.
1027 priority = c->actions[result];
1031 * We're higher than any previous priority, remember this
1032 * return code and priority.
1034 if (priority > entry->priority) {
1035 entry->result = result;
1036 entry->priority = priority;
1041 * If we're processing a "case" statement, we return once
1042 * it's done, rather than going to the next "case" statement.
1044 if (c->type == MOD_CASE) return true;
1048 * If we've been told to stop processing
1051 if (entry->unwind != 0) {
1052 RDEBUG2("%.*s # unwind to enclosing %s", depth + 1, modcall_spaces,
1053 group_name[entry->unwind]);
1059 entry->c = entry->c->next;
1061 if (entry->c) goto redo;
1071 * @brief Call a module, iteratively, with a local stack, rather than
1072 * recursively. What did Paul Graham say about Lisp...?
1074 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1076 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1079 memset(stack, 0, sizeof(stack));
1082 * Set up the initial stack frame.
1085 stack[0].result = default_component_results[component];
1086 stack[0].priority = 0;
1087 stack[0].unwind = 0;
1090 * Call the main handler.
1092 if (!modcall_recurse(request, component, 0, &stack[0])) {
1093 return RLM_MODULE_FAIL;
1097 * Return the result.
1099 return stack[0].result;
1104 static char const *action2str(int action)
1106 static char buf[32];
1107 if(action==MOD_ACTION_RETURN)
1109 if(action==MOD_ACTION_REJECT)
1111 snprintf(buf, sizeof buf, "%d", action);
1115 /* If you suspect a bug in the parser, you'll want to use these dump
1116 * functions. dump_tree should reproduce a whole tree exactly as it was found
1117 * in radiusd.conf, but in long form (all actions explicitly defined) */
1118 static void dump_mc(modcallable *c, int indent)
1122 if(c->type==MOD_SINGLE) {
1123 modsingle *single = mod_callabletosingle(c);
1124 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1125 single->modinst->name);
1126 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1127 modgroup *g = mod_callabletogroup(c);
1129 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1130 group_name[c->type]);
1131 for(p = g->children;p;p = p->next)
1132 dump_mc(p, indent+1);
1133 } /* else ignore it for now */
1135 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1136 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1137 fr_int2str(mod_rcode_table, i, "<invalid>"),
1138 action2str(c->actions[i]));
1141 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1144 static void dump_tree(rlm_components_t comp, modcallable *c)
1146 DEBUG("[%s]", comp2str[comp]);
1150 #define dump_tree(a, b)
1153 /* These are the default actions. For each component, the group{} block
1154 * behaves like the code from the old module_*() function. redundant{} and
1155 * append{} are based on my guesses of what they will be used for. --Pac. */
1157 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1163 MOD_ACTION_RETURN, /* reject */
1165 MOD_ACTION_RETURN, /* ok */
1166 MOD_ACTION_RETURN, /* handled */
1168 MOD_ACTION_RETURN, /* userlock */
1169 MOD_ACTION_RETURN, /* notfound */
1175 MOD_ACTION_RETURN, /* reject */
1177 MOD_ACTION_RETURN, /* ok */
1178 MOD_ACTION_RETURN, /* handled */
1179 MOD_ACTION_RETURN, /* invalid */
1180 MOD_ACTION_RETURN, /* userlock */
1181 MOD_ACTION_RETURN, /* notfound */
1182 MOD_ACTION_RETURN, /* noop */
1183 MOD_ACTION_RETURN /* updated */
1187 MOD_ACTION_RETURN, /* reject */
1189 MOD_ACTION_RETURN, /* ok */
1190 MOD_ACTION_RETURN, /* handled */
1191 MOD_ACTION_RETURN, /* invalid */
1192 MOD_ACTION_RETURN, /* userlock */
1194 MOD_ACTION_RETURN, /* noop */
1195 MOD_ACTION_RETURN /* updated */
1202 MOD_ACTION_RETURN, /* reject */
1203 MOD_ACTION_RETURN, /* fail */
1205 MOD_ACTION_RETURN, /* handled */
1206 MOD_ACTION_RETURN, /* invalid */
1207 MOD_ACTION_RETURN, /* userlock */
1214 MOD_ACTION_RETURN, /* reject */
1216 MOD_ACTION_RETURN, /* ok */
1217 MOD_ACTION_RETURN, /* handled */
1218 MOD_ACTION_RETURN, /* invalid */
1219 MOD_ACTION_RETURN, /* userlock */
1220 MOD_ACTION_RETURN, /* notfound */
1221 MOD_ACTION_RETURN, /* noop */
1222 MOD_ACTION_RETURN /* updated */
1226 MOD_ACTION_RETURN, /* reject */
1228 MOD_ACTION_RETURN, /* ok */
1229 MOD_ACTION_RETURN, /* handled */
1230 MOD_ACTION_RETURN, /* invalid */
1231 MOD_ACTION_RETURN, /* userlock */
1233 MOD_ACTION_RETURN, /* noop */
1234 MOD_ACTION_RETURN /* updated */
1241 MOD_ACTION_RETURN, /* reject */
1242 MOD_ACTION_RETURN, /* fail */
1244 MOD_ACTION_RETURN, /* handled */
1245 MOD_ACTION_RETURN, /* invalid */
1246 MOD_ACTION_RETURN, /* userlock */
1247 MOD_ACTION_RETURN, /* notfound */
1253 MOD_ACTION_RETURN, /* reject */
1255 MOD_ACTION_RETURN, /* ok */
1256 MOD_ACTION_RETURN, /* handled */
1257 MOD_ACTION_RETURN, /* invalid */
1258 MOD_ACTION_RETURN, /* userlock */
1259 MOD_ACTION_RETURN, /* notfound */
1260 MOD_ACTION_RETURN, /* noop */
1261 MOD_ACTION_RETURN /* updated */
1265 MOD_ACTION_RETURN, /* reject */
1267 MOD_ACTION_RETURN, /* ok */
1268 MOD_ACTION_RETURN, /* handled */
1269 MOD_ACTION_RETURN, /* invalid */
1270 MOD_ACTION_RETURN, /* userlock */
1272 MOD_ACTION_RETURN, /* noop */
1273 MOD_ACTION_RETURN /* updated */
1280 MOD_ACTION_RETURN, /* reject */
1281 MOD_ACTION_RETURN, /* fail */
1283 MOD_ACTION_RETURN, /* handled */
1284 MOD_ACTION_RETURN, /* invalid */
1285 MOD_ACTION_RETURN, /* userlock */
1286 MOD_ACTION_RETURN, /* notfound */
1294 MOD_ACTION_RETURN, /* ok */
1295 MOD_ACTION_RETURN, /* handled */
1304 MOD_ACTION_RETURN, /* reject */
1306 MOD_ACTION_RETURN, /* ok */
1307 MOD_ACTION_RETURN, /* handled */
1308 MOD_ACTION_RETURN, /* invalid */
1309 MOD_ACTION_RETURN, /* userlock */
1311 MOD_ACTION_RETURN, /* noop */
1312 MOD_ACTION_RETURN /* updated */
1319 MOD_ACTION_RETURN, /* reject */
1321 MOD_ACTION_RETURN, /* ok */
1322 MOD_ACTION_RETURN, /* handled */
1323 MOD_ACTION_RETURN, /* invalid */
1324 MOD_ACTION_RETURN, /* userlock */
1325 MOD_ACTION_RETURN, /* notfound */
1326 MOD_ACTION_RETURN, /* noop */
1327 MOD_ACTION_RETURN /* updated */
1331 MOD_ACTION_RETURN, /* reject */
1333 MOD_ACTION_RETURN, /* ok */
1334 MOD_ACTION_RETURN, /* handled */
1335 MOD_ACTION_RETURN, /* invalid */
1336 MOD_ACTION_RETURN, /* userlock */
1337 MOD_ACTION_RETURN, /* notfound */
1338 MOD_ACTION_RETURN, /* noop */
1339 MOD_ACTION_RETURN /* updated */
1343 MOD_ACTION_RETURN, /* reject */
1345 MOD_ACTION_RETURN, /* ok */
1346 MOD_ACTION_RETURN, /* handled */
1347 MOD_ACTION_RETURN, /* invalid */
1348 MOD_ACTION_RETURN, /* userlock */
1349 MOD_ACTION_RETURN, /* notfound */
1350 MOD_ACTION_RETURN, /* noop */
1351 MOD_ACTION_RETURN /* updated */
1358 MOD_ACTION_RETURN, /* reject */
1359 MOD_ACTION_RETURN, /* fail */
1361 MOD_ACTION_RETURN, /* handled */
1362 MOD_ACTION_RETURN, /* invalid */
1363 MOD_ACTION_RETURN, /* userlock */
1370 MOD_ACTION_RETURN, /* reject */
1372 MOD_ACTION_RETURN, /* ok */
1373 MOD_ACTION_RETURN, /* handled */
1374 MOD_ACTION_RETURN, /* invalid */
1375 MOD_ACTION_RETURN, /* userlock */
1376 MOD_ACTION_RETURN, /* notfound */
1377 MOD_ACTION_RETURN, /* noop */
1378 MOD_ACTION_RETURN /* updated */
1382 MOD_ACTION_RETURN, /* reject */
1384 MOD_ACTION_RETURN, /* ok */
1385 MOD_ACTION_RETURN, /* handled */
1386 MOD_ACTION_RETURN, /* invalid */
1387 MOD_ACTION_RETURN, /* userlock */
1389 MOD_ACTION_RETURN, /* noop */
1390 MOD_ACTION_RETURN /* updated */
1397 MOD_ACTION_RETURN, /* reject */
1398 MOD_ACTION_RETURN, /* fail */
1400 MOD_ACTION_RETURN, /* handled */
1401 MOD_ACTION_RETURN, /* invalid */
1402 MOD_ACTION_RETURN, /* userlock */
1409 MOD_ACTION_RETURN, /* reject */
1411 MOD_ACTION_RETURN, /* ok */
1412 MOD_ACTION_RETURN, /* handled */
1413 MOD_ACTION_RETURN, /* invalid */
1414 MOD_ACTION_RETURN, /* userlock */
1415 MOD_ACTION_RETURN, /* notfound */
1416 MOD_ACTION_RETURN, /* noop */
1417 MOD_ACTION_RETURN /* updated */
1421 MOD_ACTION_RETURN, /* reject */
1423 MOD_ACTION_RETURN, /* ok */
1424 MOD_ACTION_RETURN, /* handled */
1425 MOD_ACTION_RETURN, /* invalid */
1426 MOD_ACTION_RETURN, /* userlock */
1428 MOD_ACTION_RETURN, /* noop */
1429 MOD_ACTION_RETURN /* updated */
1436 MOD_ACTION_RETURN, /* reject */
1437 MOD_ACTION_RETURN, /* fail */
1439 MOD_ACTION_RETURN, /* handled */
1440 MOD_ACTION_RETURN, /* invalid */
1441 MOD_ACTION_RETURN, /* userlock */
1448 MOD_ACTION_RETURN, /* reject */
1450 MOD_ACTION_RETURN, /* ok */
1451 MOD_ACTION_RETURN, /* handled */
1452 MOD_ACTION_RETURN, /* invalid */
1453 MOD_ACTION_RETURN, /* userlock */
1454 MOD_ACTION_RETURN, /* notfound */
1455 MOD_ACTION_RETURN, /* noop */
1456 MOD_ACTION_RETURN /* updated */
1460 MOD_ACTION_RETURN, /* reject */
1462 MOD_ACTION_RETURN, /* ok */
1463 MOD_ACTION_RETURN, /* handled */
1464 MOD_ACTION_RETURN, /* invalid */
1465 MOD_ACTION_RETURN, /* userlock */
1467 MOD_ACTION_RETURN, /* noop */
1468 MOD_ACTION_RETURN /* updated */
1477 MOD_ACTION_RETURN, /* reject */
1478 MOD_ACTION_RETURN, /* fail */
1480 MOD_ACTION_RETURN, /* handled */
1481 MOD_ACTION_RETURN, /* invalid */
1482 MOD_ACTION_RETURN, /* userlock */
1489 MOD_ACTION_RETURN, /* reject */
1491 MOD_ACTION_RETURN, /* ok */
1492 MOD_ACTION_RETURN, /* handled */
1493 MOD_ACTION_RETURN, /* invalid */
1494 MOD_ACTION_RETURN, /* userlock */
1495 MOD_ACTION_RETURN, /* notfound */
1496 MOD_ACTION_RETURN, /* noop */
1497 MOD_ACTION_RETURN /* updated */
1501 MOD_ACTION_RETURN, /* reject */
1503 MOD_ACTION_RETURN, /* ok */
1504 MOD_ACTION_RETURN, /* handled */
1505 MOD_ACTION_RETURN, /* invalid */
1506 MOD_ACTION_RETURN, /* userlock */
1508 MOD_ACTION_RETURN, /* noop */
1509 MOD_ACTION_RETURN /* updated */
1516 MOD_ACTION_RETURN, /* reject */
1517 MOD_ACTION_RETURN, /* fail */
1519 MOD_ACTION_RETURN, /* handled */
1520 MOD_ACTION_RETURN, /* invalid */
1521 MOD_ACTION_RETURN, /* userlock */
1528 MOD_ACTION_RETURN, /* reject */
1530 MOD_ACTION_RETURN, /* ok */
1531 MOD_ACTION_RETURN, /* handled */
1532 MOD_ACTION_RETURN, /* invalid */
1533 MOD_ACTION_RETURN, /* userlock */
1534 MOD_ACTION_RETURN, /* notfound */
1535 MOD_ACTION_RETURN, /* noop */
1536 MOD_ACTION_RETURN /* updated */
1540 MOD_ACTION_RETURN, /* reject */
1542 MOD_ACTION_RETURN, /* ok */
1543 MOD_ACTION_RETURN, /* handled */
1544 MOD_ACTION_RETURN, /* invalid */
1545 MOD_ACTION_RETURN, /* userlock */
1547 MOD_ACTION_RETURN, /* noop */
1548 MOD_ACTION_RETURN /* updated */
1556 static modcallable *do_compile_modupdate(modcallable *parent, UNUSED rlm_components_t component,
1557 CONF_SECTION *cs, char const *name2)
1561 modcallable *csingle;
1562 value_pair_map_t *map, *head = NULL;
1566 * This looks at cs->name2 to determine which list to update
1568 rcode = radius_attrmap(cs, &head, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, 128);
1569 if (rcode < 0) return NULL; /* message already printed */
1572 cf_log_err_cs(cs, "'update' sections cannot be empty");
1576 for (map = head, ci = cf_item_find_next(cs, NULL);
1578 map = map->next, ci = cf_item_find_next(cs, ci)) {
1580 * Can't copy an xlat expansion or literal into a list,
1581 * we don't know what type of attribute we'd need
1584 * The only exception is where were using a unary
1587 if ((map->dst->type == VPT_TYPE_LIST) &&
1588 (map->op != T_OP_CMP_FALSE) &&
1589 ((map->src->type == VPT_TYPE_XLAT) || (map->src->type == VPT_TYPE_LITERAL))) {
1590 cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
1596 * If LHS is an attribute, and RHS is a literal, we can
1597 * preparse the information into a VPT_TYPE_DATA.
1599 * Unless it's a unary operator in which case we
1602 if ((map->dst->type == VPT_TYPE_ATTR) && (map->op != T_OP_CMP_FALSE) &&
1603 (map->src->type == VPT_TYPE_LITERAL)) {
1606 cp = cf_itemtopair(ci);
1607 rad_assert(cp != NULL);
1610 * It's a literal string, just copy it.
1611 * Don't escape anything.
1613 if ((map->dst->vpt_da->type == PW_TYPE_STRING) &&
1614 (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
1617 map->src->vpt_value = vpd = talloc_zero(map->src, value_data_t);
1618 rad_assert(vpd != NULL);
1620 vpd->strvalue = talloc_typed_strdup(vpd, map->src->name);
1621 rad_assert(vpd->strvalue != NULL);
1623 map->src->type = VPT_TYPE_DATA;
1624 map->src->vpt_da = map->dst->vpt_da;
1625 map->src->vpt_length = talloc_array_length(vpd->strvalue) - 1;
1627 if (!radius_cast_tmpl(map->src, map->dst->vpt_da)) {
1628 cf_log_err(map->ci, "%s", fr_strerror());
1633 } /* else we can't precompile the data */
1634 } /* loop over the conf_pairs in the update section */
1636 g = rad_malloc(sizeof(*g)); /* never fails */
1637 memset(g, 0, sizeof(*g));
1639 csingle = mod_grouptocallable(g);
1641 csingle->parent = parent;
1642 csingle->next = NULL;
1645 csingle->name = name2;
1649 csingle->type = MOD_UPDATE;
1650 csingle->method = component;
1652 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1653 sizeof(csingle->actions));
1655 g->grouptype = GROUPTYPE_SIMPLE;
1664 static modcallable *do_compile_modswitch(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1669 bool had_seen_default = false;
1670 modcallable *csingle;
1672 value_pair_tmpl_t *vpt;
1674 name2 = cf_section_name2(cs);
1677 "You must specify a variable to switch over for 'switch'");
1681 if (!cf_item_find_next(cs, NULL)) {
1682 cf_log_err_cs(cs, "'switch' statements cannot be empty");
1687 * Create the template. If we fail, AND it's a bare word
1688 * with &Foo-Bar, it MAY be an attribute defined by a
1689 * module. Allow it for now. The pass2 checks below
1692 type = cf_section_name2_type(cs);
1693 vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1694 if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1695 cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
1700 * Otherwise a NULL vpt may refer to an attribute defined
1701 * by a module. That is checked in pass 2.
1705 * Walk through the children of the switch section,
1706 * ensuring that they're all 'case' statements
1708 for (ci=cf_item_find_next(cs, NULL);
1710 ci=cf_item_find_next(cs, ci)) {
1711 CONF_SECTION *subcs;
1714 if (!cf_item_is_section(ci)) {
1715 if (!cf_item_is_pair(ci)) continue;
1717 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1722 subcs = cf_itemtosection(ci); /* can't return NULL */
1723 name1 = cf_section_name1(subcs);
1725 if (strcmp(name1, "case") != 0) {
1726 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1731 name2 = cf_section_name2(subcs);
1732 if (!name2 && !had_seen_default) {
1733 had_seen_default = true;
1737 if (!name2 || (name2[0] == '\0')) {
1738 cf_log_err(ci, "\"case\" sections must have a name");
1744 csingle = do_compile_modgroup(parent, component, cs,
1753 g = mod_callabletogroup(csingle);
1759 static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1763 modcallable *csingle;
1765 value_pair_tmpl_t *vpt;
1767 if (!parent || (parent->type != MOD_SWITCH)) {
1768 cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
1773 * case THING means "match THING"
1774 * case means "match anything"
1776 name2 = cf_section_name2(cs);
1780 type = cf_section_name2_type(cs);
1782 vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1783 if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1784 cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
1789 * Otherwise a NULL vpt may refer to an attribute defined
1790 * by a module. That is checked in pass 2.
1797 csingle= do_compile_modgroup(parent, component, cs,
1807 * The interpretor expects this to be NULL for the
1808 * default case. do_compile_modgroup sets it to name2,
1809 * unless name2 is NULL, in which case it sets it to name1.
1811 csingle->name = name2;
1813 g = mod_callabletogroup(csingle);
1817 * Set all of it's codes to return, so that
1818 * when we pick a 'case' statement, we don't
1819 * fall through to processing the next one.
1821 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1822 csingle->actions[i] = MOD_ACTION_RETURN;
1828 static modcallable *do_compile_modforeach(modcallable *parent,
1829 UNUSED rlm_components_t component, CONF_SECTION *cs)
1833 modcallable *csingle;
1835 value_pair_tmpl_t *vpt;
1837 name2 = cf_section_name2(cs);
1840 "You must specify an attribute to loop over in 'foreach'");
1844 if (!cf_item_find_next(cs, NULL)) {
1845 cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
1850 * Create the template. If we fail, AND it's a bare word
1851 * with &Foo-Bar, it MAY be an attribute defined by a
1852 * module. Allow it for now. The pass2 checks below
1855 type = cf_section_name2_type(cs);
1856 vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1857 if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1858 cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
1862 if (vpt && (vpt->type != VPT_TYPE_ATTR)) {
1863 cf_log_err_cs(cs, "MUST use attribute reference in 'foreach'");
1867 csingle = do_compile_modgroup(parent, component, cs,
1868 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
1876 g = mod_callabletogroup(csingle);
1882 static modcallable *do_compile_modbreak(modcallable *parent,
1883 rlm_components_t component, CONF_ITEM const *ci)
1885 CONF_SECTION const *cs = NULL;
1887 for (cs = cf_item_parent(ci);
1889 cs = cf_item_parent(cf_sectiontoitem(cs))) {
1890 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
1896 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
1900 return do_compile_modgroup(parent, component, NULL,
1901 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
1906 static modcallable *do_compile_modserver(modcallable *parent,
1907 rlm_components_t component, CONF_ITEM *ci,
1912 modcallable *csingle;
1913 CONF_SECTION *subcs;
1916 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
1918 cf_log_err(ci, "Server %s has no %s section",
1919 server, comp2str[component]);
1923 mr = rad_malloc(sizeof(*mr));
1924 memset(mr, 0, sizeof(*mr));
1926 csingle = mod_reftocallable(mr);
1927 csingle->parent = parent;
1928 csingle->next = NULL;
1929 csingle->name = name;
1930 csingle->type = MOD_REFERENCE;
1931 csingle->method = component;
1933 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1934 sizeof(csingle->actions));
1936 mr->ref_name = strdup(server);
1942 static modcallable *do_compile_modxlat(modcallable *parent,
1943 rlm_components_t component, char const *fmt)
1945 modcallable *csingle;
1948 mx = rad_malloc(sizeof(*mx));
1949 memset(mx, 0, sizeof(*mx));
1951 csingle = mod_xlattocallable(mx);
1952 csingle->parent = parent;
1953 csingle->next = NULL;
1954 csingle->name = "expand";
1955 csingle->type = MOD_XLAT;
1956 csingle->method = component;
1958 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1959 sizeof(csingle->actions));
1961 mx->xlat_name = strdup(fmt);
1962 if (fmt[0] != '%') {
1966 strcpy(mx->xlat_name, fmt + 1);
1967 p = strrchr(mx->xlat_name, '`');
1975 * redundant, etc. can refer to modules or groups, but not much else.
1977 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
1981 for (ci=cf_item_find_next(cs, NULL);
1983 ci=cf_item_find_next(cs, ci)) {
1985 * If we're a redundant, etc. group, then the
1986 * intention is to call modules, rather than
1987 * processing logic. These checks aren't
1988 * *strictly* necessary, but they keep the users
1989 * from doing crazy things.
1991 if (cf_item_is_section(ci)) {
1992 CONF_SECTION *subcs = cf_itemtosection(ci);
1993 char const *name1 = cf_section_name1(subcs);
1995 if ((strcmp(name1, "if") == 0) ||
1996 (strcmp(name1, "else") == 0) ||
1997 (strcmp(name1, "elsif") == 0) ||
1998 (strcmp(name1, "update") == 0) ||
1999 (strcmp(name1, "switch") == 0) ||
2000 (strcmp(name1, "case") == 0)) {
2001 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
2008 if (cf_item_is_pair(ci)) {
2009 CONF_PAIR *cp = cf_itemtopair(ci);
2010 if (cf_pair_value(cp) != NULL) {
2012 "Entry with no value is invalid");
2023 * Compile one entry of a module call.
2025 static modcallable *do_compile_modsingle(modcallable *parent,
2026 rlm_components_t component, CONF_ITEM *ci,
2028 char const **modname)
2030 char const *modrefname;
2032 modcallable *csingle;
2033 module_instance_t *this;
2034 CONF_SECTION *cs, *subcs, *modules;
2035 char const *realname;
2037 if (cf_item_is_section(ci)) {
2040 cs = cf_itemtosection(ci);
2041 modrefname = cf_section_name1(cs);
2042 name2 = cf_section_name2(cs);
2043 if (!name2) name2 = "";
2046 * group{}, redundant{}, or append{} may appear
2047 * where a single module instance was expected.
2048 * In that case, we hand it off to
2051 if (strcmp(modrefname, "group") == 0) {
2053 return do_compile_modgroup(parent, component, cs,
2055 grouptype, MOD_GROUP);
2057 } else if (strcmp(modrefname, "redundant") == 0) {
2060 if (!all_children_are_modules(cs, modrefname)) {
2064 return do_compile_modgroup(parent, component, cs,
2065 GROUPTYPE_REDUNDANT,
2066 grouptype, MOD_GROUP);
2068 } else if (strcmp(modrefname, "append") == 0) {
2070 return do_compile_modgroup(parent, component, cs,
2072 grouptype, MOD_GROUP);
2074 } else if (strcmp(modrefname, "load-balance") == 0) {
2077 if (!all_children_are_modules(cs, modrefname)) {
2081 return do_compile_modgroup(parent, component, cs,
2083 grouptype, MOD_LOAD_BALANCE);
2085 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
2088 if (!all_children_are_modules(cs, modrefname)) {
2092 return do_compile_modgroup(parent, component, cs,
2093 GROUPTYPE_REDUNDANT,
2094 grouptype, MOD_REDUNDANT_LOAD_BALANCE);
2097 } else if (strcmp(modrefname, "if") == 0) {
2098 if (!cf_section_name2(cs)) {
2099 cf_log_err(ci, "'if' without condition");
2104 csingle= do_compile_modgroup(parent, component, cs,
2107 if (!csingle) return NULL;
2112 } else if (strcmp(modrefname, "elsif") == 0) {
2114 ((parent->type == MOD_LOAD_BALANCE) ||
2115 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2116 cf_log_err(ci, "'elsif' cannot be used in this section");
2120 if (!cf_section_name2(cs)) {
2121 cf_log_err(ci, "'elsif' without condition");
2126 return do_compile_modgroup(parent, component, cs,
2128 grouptype, MOD_ELSIF);
2130 } else if (strcmp(modrefname, "else") == 0) {
2132 ((parent->type == MOD_LOAD_BALANCE) ||
2133 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2134 cf_log_err(ci, "'else' cannot be used in this section section");
2138 if (cf_section_name2(cs)) {
2139 cf_log_err(ci, "Cannot have conditions on 'else'");
2144 return do_compile_modgroup(parent, component, cs,
2146 grouptype, MOD_ELSE);
2148 } else if (strcmp(modrefname, "update") == 0) {
2151 return do_compile_modupdate(parent, component, cs,
2154 } else if (strcmp(modrefname, "switch") == 0) {
2157 return do_compile_modswitch(parent, component, cs);
2159 } else if (strcmp(modrefname, "case") == 0) {
2162 return do_compile_modcase(parent, component, cs);
2164 } else if (strcmp(modrefname, "foreach") == 0) {
2167 return do_compile_modforeach(parent, component, cs);
2170 } /* else it's something like sql { fail = 1 ...} */
2172 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2176 * Else it's a module reference, with updated return
2181 CONF_PAIR *cp = cf_itemtopair(ci);
2182 modrefname = cf_pair_attr(cp);
2185 * Actions (ok = 1), etc. are orthoganal to just
2186 * about everything else.
2188 if (cf_pair_value(cp) != NULL) {
2189 cf_log_err(ci, "Entry is not a reference to a module");
2193 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2194 (modrefname[0] == '`')) {
2195 return do_compile_modxlat(parent, component,
2200 * See if the module is a virtual one. If so,
2201 * return that, rather than doing anything here.
2204 cs = cf_section_find("instantiate");
2205 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
2208 (cs = cf_section_find("policy")) != NULL) {
2211 snprintf(buffer, sizeof(buffer), "%s.%s",
2212 modrefname, comp2str[component]);
2215 * Prefer name.section, then name.
2217 subcs = cf_section_sub_find_name2(cs, NULL,
2220 subcs = cf_section_sub_find_name2(cs, NULL,
2226 * Allow policies to over-ride module names.
2227 * i.e. the "sql" policy can do some extra things,
2228 * and then call the "sql" module.
2230 for (loop = cf_item_parent(ci);
2232 loop = cf_item_parent(cf_sectiontoitem(loop))) {
2233 if (loop == subcs) {
2240 * redundant foo {} is a single.
2242 if (cf_section_name2(subcs)) {
2243 return do_compile_modsingle(parent,
2245 cf_sectiontoitem(subcs),
2250 * foo {} is a group.
2252 return do_compile_modgroup(parent,
2256 grouptype, MOD_GROUP);
2262 if (strcmp(modrefname, "break") == 0) {
2263 return do_compile_modbreak(parent, component, ci);
2268 * Not a virtual module. It must be a real module.
2270 modules = cf_section_find("modules");
2272 realname = modrefname;
2276 * Try to load the optional module.
2278 if (realname[0] == '-') realname++;
2281 * As of v3, only known modules are in the
2282 * "modules" section.
2284 if (cf_section_sub_find_name2(modules, NULL, realname)) {
2285 this = find_module_instance(modules, realname, 1);
2286 if (!this && (realname != modrefname)) {
2292 * We were asked to MAYBE load it and it
2293 * doesn't exist. Return a soft error.
2295 if (realname != modrefname) {
2296 *modname = modrefname;
2307 * Maybe it's module.method
2309 p = strrchr(modrefname, '.');
2310 if (p) for (i = RLM_COMPONENT_AUTH;
2311 i < RLM_COMPONENT_COUNT;
2313 if (strcmp(p + 1, comp2str[i]) == 0) {
2316 strlcpy(buffer, modrefname, sizeof(buffer));
2317 buffer[p - modrefname] = '\0';
2320 this = find_module_instance(modules, buffer, 1);
2322 !this->entry->module->methods[i]) {
2324 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
2333 * Call a server. This should really be deleted...
2335 if (strncmp(modrefname, "server[", 7) == 0) {
2338 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2339 p = strrchr(buffer, ']');
2340 if (!p || p[1] != '\0' || (p == buffer)) {
2341 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2346 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2348 cf_log_err(ci, "No such server \"%s\".", buffer);
2352 return do_compile_modserver(parent, component, ci,
2353 modrefname, cs, buffer);
2357 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
2362 * We know it's all OK, allocate the structures, and fill
2365 single = rad_malloc(sizeof(*single));
2366 memset(single, 0, sizeof(*single));
2367 csingle = mod_singletocallable(single);
2368 csingle->parent = parent;
2369 csingle->next = NULL;
2370 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2371 memcpy(csingle->actions, defaultactions[component][grouptype],
2372 sizeof csingle->actions);
2373 } else { /* inside Auth-Type has different rules */
2374 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2375 sizeof csingle->actions);
2377 rad_assert(modrefname != NULL);
2378 csingle->name = realname;
2379 csingle->type = MOD_SINGLE;
2380 csingle->method = component;
2383 * Singles can override the actions, virtual modules cannot.
2385 * FIXME: We may want to re-visit how to do this...
2386 * maybe a csingle as a ref?
2388 if (cf_item_is_section(ci)) {
2391 cs = cf_itemtosection(ci);
2392 for (csi=cf_item_find_next(cs, NULL);
2394 csi=cf_item_find_next(cs, csi)) {
2396 if (cf_item_is_section(csi)) {
2397 cf_log_err(csi, "Subsection of module instance call not allowed");
2398 modcallable_free(&csingle);
2402 if (!cf_item_is_pair(csi)) continue;
2404 if (!compile_action(csingle, cf_itemtopair(csi))) {
2405 modcallable_free(&csingle);
2412 * Bail out if the module in question does not supply the
2415 if (!this->entry->module->methods[component]) {
2416 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2417 comp2str[component]);
2418 modcallable_free(&csingle);
2422 single->modinst = this;
2423 *modname = this->entry->module->name;
2427 modcallable *compile_modsingle(modcallable **parent,
2428 rlm_components_t component, CONF_ITEM *ci,
2429 char const **modname)
2436 CONF_SECTION *parentcs;
2438 g = rad_malloc(sizeof *g);
2439 memset(g, 0, sizeof(*g));
2440 g->grouptype = GROUPTYPE_SIMPLE;
2441 c = mod_grouptocallable(g);
2444 defaultactions[component][GROUPTYPE_SIMPLE],
2445 sizeof(c->actions));
2447 parentcs = cf_item_parent(ci);
2448 c->name = cf_section_name2(parentcs);
2450 c->name = cf_section_name1(parentcs);
2453 c->type = MOD_GROUP;
2454 c->method = component;
2457 *parent = mod_grouptocallable(g);
2460 ret = do_compile_modsingle(*parent, component, ci,
2463 dump_tree(component, ret);
2469 * Internal compile group code.
2471 static modcallable *do_compile_modgroup(modcallable *parent,
2472 rlm_components_t component, CONF_SECTION *cs,
2473 int grouptype, int parentgrouptype, int mod_type)
2480 g = rad_malloc(sizeof(*g));
2481 memset(g, 0, sizeof(*g));
2482 g->grouptype = grouptype;
2486 c = mod_grouptocallable(g);
2490 memset(c->actions, 0, sizeof(c->actions));
2492 if (!cs) { /* only for "break" */
2498 * Remember the name for printing, etc.
2500 * FIXME: We may also want to put the names into a
2501 * rbtree, so that groups can reference each other...
2503 c->name = cf_section_name2(cs);
2505 c->name = cf_section_name1(cs);
2506 if (strcmp(c->name, "group") == 0) {
2508 } else if (c->type == MOD_GROUP) {
2509 c->type = MOD_POLICY;
2515 * Do load-time optimizations
2517 if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
2520 rad_assert(parent != NULL);
2522 if (c->type == MOD_IF) {
2523 g->cond = cf_data_find(g->cs, "if");
2524 rad_assert(g->cond != NULL);
2527 if (g->cond->type == COND_TYPE_FALSE) {
2528 INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
2529 group_name[g->mc.type],
2530 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2534 } else if (c->type == MOD_ELSIF) {
2536 g->cond = cf_data_find(g->cs, "if");
2537 rad_assert(g->cond != NULL);
2539 rad_assert(parent != NULL);
2540 p = mod_callabletogroup(parent);
2542 rad_assert(p->tail != NULL);
2544 f = mod_callabletogroup(p->tail);
2545 rad_assert((f->mc.type == MOD_IF) ||
2546 (f->mc.type == MOD_ELSIF));
2549 * If we took the previous condition, we
2550 * don't need to take this one.
2552 * We reset our condition to 'true', so
2553 * that subsequent sections can check
2554 * that they don't need to be executed.
2556 if (f->cond->type == COND_TYPE_TRUE) {
2558 INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
2559 group_name[g->mc.type],
2560 group_name[f->mc.type],
2561 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2568 rad_assert(c->type == MOD_ELSE);
2570 rad_assert(parent != NULL);
2571 p = mod_callabletogroup(parent);
2573 rad_assert(p->tail != NULL);
2575 f = mod_callabletogroup(p->tail);
2576 rad_assert((f->mc.type == MOD_IF) ||
2577 (f->mc.type == MOD_ELSIF));
2580 * If we took the previous condition, we
2581 * don't need to take this one.
2583 if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
2587 * Else we need to compile this section
2593 * Loop over the children of this group.
2595 for (ci=cf_item_find_next(cs, NULL);
2597 ci=cf_item_find_next(cs, ci)) {
2600 * Sections are references to other groups, or
2601 * to modules with updated return codes.
2603 if (cf_item_is_section(ci)) {
2604 char const *junk = NULL;
2605 modcallable *single;
2606 CONF_SECTION *subcs = cf_itemtosection(ci);
2608 single = do_compile_modsingle(c, component, ci,
2611 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2612 cf_section_name1(subcs));
2613 modcallable_free(&c);
2616 add_child(g, single);
2618 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2622 char const *attr, *value;
2623 CONF_PAIR *cp = cf_itemtopair(ci);
2625 attr = cf_pair_attr(cp);
2626 value = cf_pair_value(cp);
2629 * A CONF_PAIR is either a module
2630 * instance with no actions
2634 modcallable *single;
2635 char const *junk = NULL;
2637 single = do_compile_modsingle(c,
2643 if (cf_item_is_pair(ci) &&
2644 cf_pair_attr(cf_itemtopair(ci))[0] == '-') {
2649 "Failed to parse \"%s\" entry.",
2651 modcallable_free(&c);
2654 add_child(g, single);
2657 * Or a module instance with action.
2659 } else if (!compile_action(c, cp)) {
2660 modcallable_free(&c);
2662 } /* else it worked */
2668 * Set the default actions, if they haven't already been
2671 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2672 if (!c->actions[i]) {
2673 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2674 c->actions[i] = defaultactions[component][parentgrouptype][i];
2675 } else { /* inside Auth-Type has different rules */
2676 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2682 * FIXME: If there are no children, return NULL?
2684 return mod_grouptocallable(g);
2687 modcallable *compile_modgroup(modcallable *parent,
2688 rlm_components_t component, CONF_SECTION *cs)
2690 modcallable *ret = do_compile_modgroup(parent, component, cs,
2692 GROUPTYPE_SIMPLE, MOD_GROUP);
2694 if (debug_flag > 3) {
2695 modcall_debug(ret, 2);
2701 void add_to_modcallable(modcallable *parent, modcallable *this)
2705 rad_assert(this != NULL);
2706 rad_assert(parent != NULL);
2708 g = mod_callabletogroup(parent);
2713 void modcallable_free(modcallable **pc)
2715 modcallable *c, *loop, *next;
2717 if (!pc || !*pc) return;
2721 if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
2722 modgroup *g = mod_callabletogroup(c);
2724 if (g->children) for (loop = g->children;
2728 modcallable_free(&loop);
2730 talloc_free(g->map);
2738 static char const spaces[] = " ";
2740 static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t **pvpt, bool convert)
2746 value_pair_tmpl_t *vpt;
2750 rad_assert(vpt->type == VPT_TYPE_XLAT);
2752 fmt = talloc_typed_strdup(vpt, vpt->name);
2753 slen = xlat_tokenize(vpt, fmt, &head, &error);
2756 char const *prefix = "";
2757 char const *p = vpt->name;
2758 size_t indent = -slen;
2760 if (indent >= sizeof(spaces)) {
2761 size_t offset = (indent - (sizeof(spaces) - 1)) + (sizeof(spaces) * 0.75);
2768 cf_log_err(ci, "Failed parsing expanded string:");
2769 cf_log_err(ci, "%s%s", prefix, p);
2770 cf_log_err(ci, "%s%.*s^ %s", prefix, (int) indent, spaces, error);
2776 * Convert %{Attribute-Name} to &Attribute-Name
2779 value_pair_tmpl_t *attr;
2781 attr = radius_xlat2tmpl(talloc_parent(vpt), head);
2783 if (cf_item_is_pair(ci)) {
2784 CONF_PAIR *cp = cf_itemtopair(ci);
2786 WARN("%s[%d] Please change %%{%s} to &%s",
2787 cf_pair_filename(cp), cf_pair_lineno(cp),
2788 attr->name, attr->name);
2790 CONF_SECTION *cs = cf_itemtosection(ci);
2792 WARN("%s[%d] Please change %%{%s} to &%s",
2793 cf_section_filename(cs), cf_section_lineno(cs),
2794 attr->name, attr->name);
2803 * Re-write it to be a pre-parsed XLAT structure.
2805 vpt->type = VPT_TYPE_XLAT_STRUCT;
2806 vpt->vpt_xlat = head;
2813 static int _free_compiled_regex(regex_t *preg)
2819 static bool pass2_regex_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
2824 rad_assert(vpt->type == VPT_TYPE_REGEX);
2827 * Expanded at run-time. We can't precompile it.
2829 if (strchr(vpt->name, '%')) return true;
2831 preg = talloc_zero(vpt, regex_t);
2832 talloc_set_destructor(preg, _free_compiled_regex);
2833 if (!preg) return false;
2835 rcode = regcomp(preg, vpt->name, REG_EXTENDED | (vpt->vpt_iflag ? REG_ICASE : 0));
2838 regerror(rcode, preg, buffer, sizeof(buffer));
2840 cf_log_err(ci, "Invalid regular expression %s: %s",
2845 vpt->type = VPT_TYPE_REGEX_STRUCT;
2846 vpt->vpt_preg = preg;
2852 static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
2854 value_pair_map_t *map;
2856 if (c->type == COND_TYPE_EXISTS) {
2857 if (c->data.vpt->type == VPT_TYPE_XLAT) {
2858 return pass2_xlat_compile(c->ci, &c->data.vpt, true);
2861 rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
2864 * FIXME: fix up attribute references, too!
2870 * Maps have a paircompare fixup applied to them.
2871 * Others get ignored.
2873 if (c->pass2_fixup == PASS2_FIXUP_NONE) {
2874 if (c->type == COND_TYPE_MAP) {
2882 map = c->data.map; /* shorter */
2887 * Where "foo" is dynamically defined.
2889 if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
2890 if (!dict_valbyname(map->dst->vpt_da->attr,
2891 map->dst->vpt_da->vendor,
2893 cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
2894 map->dst->vpt_da->name,
2900 * These guys can't have a paircompare fixup applied.
2902 c->pass2_fixup = PASS2_FIXUP_NONE;
2906 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
2907 value_pair_map_t *old;
2908 value_pair_tmpl_t vpt;
2913 * It's still not an attribute. Ignore it.
2915 if (radius_parse_attr(&vpt, map->dst->name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
2916 cf_log_err(old->ci, "Failed parsing condition: %s", fr_strerror());
2917 c->pass2_fixup = PASS2_FIXUP_NONE;
2922 * Re-parse the LHS as an attribute.
2924 map = radius_str2map(c, old->dst->name, T_BARE_WORD, old->op,
2925 old->src->name, T_BARE_WORD,
2926 REQUEST_CURRENT, PAIR_LIST_REQUEST,
2927 REQUEST_CURRENT, PAIR_LIST_REQUEST);
2929 cf_log_err(old->ci, "Failed parsing condition");
2935 c->pass2_fixup = PASS2_FIXUP_NONE;
2940 * Just in case someone adds a new fixup later.
2942 rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
2943 (c->pass2_fixup == PASS2_PAIRCOMPARE));
2948 if (map->dst->type == VPT_TYPE_XLAT) {
2950 * Don't compile the LHS to an attribute
2951 * reference for now. When we do that, we've got
2952 * to check the RHS for type-specific data, and
2953 * parse it to a VPT_TYPE_DATA.
2955 if (!pass2_xlat_compile(map->ci, &map->dst, false)) {
2960 if (map->src->type == VPT_TYPE_XLAT) {
2962 * Convert the RHS to an attribute reference only
2963 * if the LHS is an attribute reference, too.
2965 * We can fix this when the code in evaluate.c
2966 * can handle strings on the LHS, and attributes
2967 * on the RHS. For now, the code in parser.c
2970 if (!pass2_xlat_compile(map->ci, &map->src, (map->dst->type == VPT_TYPE_ATTR))) {
2976 * Convert bare refs to %{Foreach-Variable-N}
2978 if ((map->dst->type == VPT_TYPE_LITERAL) &&
2979 (strncmp(map->dst->name, "Foreach-Variable-", 17) == 0)) {
2981 value_pair_tmpl_t *vpt;
2983 fmt = talloc_asprintf(map->dst, "%%{%s}", map->dst->name);
2984 vpt = radius_str2tmpl(map, fmt, T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
2986 cf_log_err(map->ci, "Failed compiling %s", map->dst->name);
2990 talloc_free(map->dst);
2995 if (map->src->type == VPT_TYPE_REGEX) {
2996 if (!pass2_regex_compile(map->ci, map->src)) {
3000 rad_assert(map->dst->type != VPT_TYPE_REGEX);
3004 * Only attributes can have a paircompare registered, and
3005 * they can only be with the current REQUEST, and only
3006 * with the request pairs.
3008 if ((map->dst->type != VPT_TYPE_ATTR) ||
3009 (map->dst->vpt_request != REQUEST_CURRENT) ||
3010 (map->dst->vpt_list != PAIR_LIST_REQUEST)) {
3014 if (!radius_find_compare(map->dst->vpt_da)) return true;
3016 if (map->src->type == VPT_TYPE_ATTR) {
3017 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
3022 if (map->src->type == VPT_TYPE_REGEX) {
3023 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
3029 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
3034 if (map->op != T_OP_CMP_EQ) {
3035 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
3041 * Mark it as requiring a paircompare() call, instead of
3044 c->pass2_fixup = PASS2_PAIRCOMPARE;
3051 * Compile the RHS of update sections to xlat_exp_t
3053 static bool modcall_pass2_update(modgroup *g)
3055 value_pair_map_t *map;
3057 for (map = g->map; map != NULL; map = map->next) {
3058 if (map->src->type == VPT_TYPE_XLAT) {
3059 rad_assert(map->src->vpt_xlat == NULL);
3062 * FIXME: compile to attribute && handle
3063 * the conversion in radius_map2vp().
3065 if (!pass2_xlat_compile(map->ci, &map->src, false)) {
3070 rad_assert(map->src->type != VPT_TYPE_REGEX);
3078 * Do a second-stage pass on compiling the modules.
3080 bool modcall_pass2(modcallable *mc)
3085 for (this = mc; this != NULL; this = this->next) {
3086 switch (this->type) {
3093 g = mod_callabletogroup(this);
3094 if (g->done_pass2) return true;
3096 if (!modcall_pass2_update(g)) {
3099 g->done_pass2 = true;
3102 case MOD_XLAT: /* @todo: pre-parse xlat's */
3108 break; /* do nothing */
3113 g = mod_callabletogroup(this);
3114 if (g->done_pass2) return true;
3117 * Don't walk over these.
3119 if ((g->cond->type == COND_TYPE_TRUE) ||
3120 (g->cond->type == COND_TYPE_FALSE)) {
3125 * The compilation code takes care of
3126 * simplifying 'true' and 'false'
3127 * conditions. For others, we have to do
3128 * a second pass to parse && compile xlats.
3130 if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
3134 if (!modcall_pass2(g->children)) return false;
3135 g->done_pass2 = true;
3141 g = mod_callabletogroup(this);
3142 if (g->done_pass2) return true;
3145 * We had &Foo-Bar, where Foo-Bar is
3146 * defined by a module.
3149 rad_assert(this->name != NULL);
3150 rad_assert(this->name[0] == '&');
3151 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3156 * Statically compile xlats
3158 if (g->vpt->type == VPT_TYPE_XLAT) goto do_case_xlat;
3161 * We may have: switch Foo-Bar {
3163 * where Foo-Bar is an attribute defined
3164 * by a module. Since there's no leading
3165 * &, it's parsed as a literal. But if
3166 * we can parse it as an attribute,
3167 * switch to using that.
3169 if (g->vpt->type == VPT_TYPE_LITERAL) {
3170 value_pair_tmpl_t *vpt;
3172 vpt = radius_str2tmpl(g->cs, this->name,
3173 cf_section_name2_type(g->cs),
3174 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3175 if (vpt->type == VPT_TYPE_ATTR) {
3176 talloc_free(g->vpt);
3182 * Warn about old-style configuration.
3184 * DEPRECATED: switch User-Name { ...
3185 * ALLOWED : switch &User-Name { ...
3187 if ((g->vpt->type == VPT_TYPE_ATTR) &&
3188 (this->name[0] != '&')) {
3189 WARN("%s[%d]: Please change %s to &%s",
3190 cf_section_filename(g->cs),
3191 cf_section_lineno(g->cs),
3192 this->name, this->name);
3195 if (!modcall_pass2(g->children)) return false;
3196 g->done_pass2 = true;
3200 g = mod_callabletogroup(this);
3201 if (g->done_pass2) return true;
3205 * The statement may refer to an
3206 * attribute which doesn't exist until
3207 * all of the modules have been loaded.
3208 * Check for that now.
3210 if (!g->vpt && this->name &&
3211 (this->name[0] == '&') &&
3212 (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
3213 g->vpt = radius_str2tmpl(g->cs, this->name,
3214 cf_section_name2_type(g->cs),
3215 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3217 cf_log_err_cs(g->cs, "Syntax error in '%s': %s",
3218 this->name, fr_strerror());
3224 * Do type-specific checks on the case statement
3226 if (g->vpt && (g->vpt->type == VPT_TYPE_LITERAL)) {
3229 rad_assert(this->parent != NULL);
3230 rad_assert(this->parent->type == MOD_SWITCH);
3232 f = mod_callabletogroup(mc->parent);
3233 rad_assert(f->vpt != NULL);
3236 * We're switching over an
3237 * attribute. Check that the
3240 if (f->vpt->type == VPT_TYPE_ATTR) {
3241 rad_assert(f->vpt->vpt_da != NULL);
3243 if (!radius_cast_tmpl(g->vpt, f->vpt->vpt_da)) {
3244 cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
3253 * Compile and sanity check xlat
3257 (g->vpt->type == VPT_TYPE_XLAT) &&
3258 (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3263 if (!modcall_pass2(g->children)) return false;
3264 g->done_pass2 = true;
3268 g = mod_callabletogroup(this);
3269 if (g->done_pass2) return true;
3272 * Already parsed, handle the children.
3274 if (g->vpt) goto check_children;
3277 * We had &Foo-Bar, where Foo-Bar is
3278 * defined by a module.
3280 rad_assert(this->name != NULL);
3281 rad_assert(this->name[0] == '&');
3282 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3285 * The statement may refer to an
3286 * attribute which doesn't exist until
3287 * all of the modules have been loaded.
3288 * Check for that now.
3290 g->vpt = radius_str2tmpl(g->cs, this->name,
3291 cf_section_name2_type(g->cs),
3292 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3294 cf_log_err_cs(g->cs, "Syntax error in '%s': %s",
3295 this->name, fr_strerror());
3300 rad_assert(g->vpt->type == VPT_TYPE_ATTR);
3301 if (g->vpt->vpt_num != NUM_ANY) {
3302 cf_log_err_cs(g->cs, "MUST NOT use array references in 'foreach'");
3305 if (!modcall_pass2(g->children)) return false;
3306 g->done_pass2 = true;
3315 case MOD_LOAD_BALANCE:
3316 case MOD_REDUNDANT_LOAD_BALANCE:
3317 g = mod_callabletogroup(this);
3318 if (g->done_pass2) return true;
3319 if (!modcall_pass2(g->children)) return false;
3320 g->done_pass2 = true;
3328 void modcall_debug(modcallable *mc, int depth)
3332 value_pair_map_t *map;
3336 for (this = mc; this != NULL; this = this->next) {
3337 switch (this->type) {
3342 modsingle *single = mod_callabletosingle(this);
3344 DEBUG("%.*s%s", depth, modcall_spaces,
3345 single->modinst->name);
3351 g = mod_callabletogroup(this);
3352 DEBUG("%.*s%s {", depth, modcall_spaces,
3353 group_name[this->type]);
3355 for (map = g->map; map != NULL; map = map->next) {
3356 radius_map2str(buffer, sizeof(buffer), map);
3357 DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
3360 DEBUG("%.*s}", depth, modcall_spaces);
3364 g = mod_callabletogroup(this);
3365 DEBUG("%.*s%s {", depth, modcall_spaces,
3366 group_name[this->type]);
3367 modcall_debug(g->children, depth + 1);
3368 DEBUG("%.*s}", depth, modcall_spaces);
3373 g = mod_callabletogroup(this);
3374 fr_cond_sprint(buffer, sizeof(buffer), g->cond);
3375 DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
3376 group_name[this->type], buffer);
3377 modcall_debug(g->children, depth + 1);
3378 DEBUG("%.*s}", depth, modcall_spaces);
3383 g = mod_callabletogroup(this);
3384 radius_tmpl2str(buffer, sizeof(buffer), g->vpt);
3385 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3386 group_name[this->type], buffer);
3387 modcall_debug(g->children, depth + 1);
3388 DEBUG("%.*s}", depth, modcall_spaces);
3393 g = mod_callabletogroup(this);
3394 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3395 group_name[this->type], this->name);
3396 modcall_debug(g->children, depth + 1);
3397 DEBUG("%.*s}", depth, modcall_spaces);
3401 DEBUG("%.*sbreak", depth, modcall_spaces);
3406 g = mod_callabletogroup(this);
3407 name1 = cf_section_name1(g->cs);
3408 if (strcmp(name1, "group") == 0) {
3409 DEBUG("%.*s%s {", depth, modcall_spaces,
3410 group_name[this->type]);
3412 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3413 name1, cf_section_name2(g->cs));
3415 modcall_debug(g->children, depth + 1);
3416 DEBUG("%.*s}", depth, modcall_spaces);
3420 case MOD_LOAD_BALANCE:
3421 case MOD_REDUNDANT_LOAD_BALANCE:
3422 g = mod_callabletogroup(this);
3423 DEBUG("%.*s%s {", depth, modcall_spaces,
3424 group_name[this->type]);
3425 modcall_debug(g->children, depth + 1);
3426 DEBUG("%.*s}", depth, modcall_spaces);