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 rad_assert(g->children != NULL);
904 for (this = g->children; this; this = this->next) {
912 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
917 MOD_LOG_OPEN_BRACE(group_name[c->type]);
919 if (c->type == MOD_LOAD_BALANCE) {
920 modcall_child(request, component,
921 depth + 1, entry, found,
928 * Loop over all children in this
929 * section. If we get FAIL, then
930 * continue. Otherwise, stop.
932 for (i = 1; i < count; i++) {
933 modcall_child(request, component,
934 depth + 1, entry, found,
936 if (c->actions[result] == MOD_ACTION_RETURN) {
942 MOD_LOG_CLOSE_BRACE();
943 goto calculate_result;
944 } /* MOD_LOAD_BALANCE */
947 * Reference another virtual server.
949 * This should really be deleted, and replaced with a
950 * more abstracted / functional version.
952 if (c->type == MOD_REFERENCE) {
953 modref *mr = mod_callabletoref(c);
954 char const *server = request->server;
956 if (server == mr->ref_name) {
957 RWDEBUG("Suppressing recursive call to server %s", server);
961 request->server = mr->ref_name;
962 RDEBUG("server %s { # nested call", mr->ref_name);
963 result = indexed_modcall(component, 0, request);
964 RDEBUG("} # server %s with nested call", mr->ref_name);
965 request->server = server;
966 goto calculate_result;
967 } /* MOD_REFERENCE */
970 * xlat a string without doing anything else
972 * This should really be deleted, and replaced with a
973 * more abstracted / functional version.
975 if (c->type == MOD_XLAT) {
976 modxlat *mx = mod_callabletoxlat(c);
980 radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
982 RDEBUG("`%s`", mx->xlat_name);
983 radius_exec_program(request, mx->xlat_name, false, true, NULL, 0,
984 EXEC_TIMEOUT, request->packet->vps, NULL);
991 * Add new module types here.
996 RDEBUG("(%s, %d) ? (%s, %d)",
997 fr_int2str(mod_rcode_table, result, "<invalid>"),
999 fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
1004 rad_assert(result != RLM_MODULE_UNKNOWN);
1007 * The child's action says return. Do so.
1009 if ((c->actions[result] == MOD_ACTION_RETURN) &&
1011 entry->result = result;
1016 * If "reject", break out of the loop and return
1019 if (c->actions[result] == MOD_ACTION_REJECT) {
1020 entry->result = RLM_MODULE_REJECT;
1025 * The array holds a default priority for this return
1026 * code. Grab it in preference to any unset priority.
1029 priority = c->actions[result];
1033 * We're higher than any previous priority, remember this
1034 * return code and priority.
1036 if (priority > entry->priority) {
1037 entry->result = result;
1038 entry->priority = priority;
1043 * If we're processing a "case" statement, we return once
1044 * it's done, rather than going to the next "case" statement.
1046 if (c->type == MOD_CASE) return true;
1050 * If we've been told to stop processing
1053 if (entry->unwind != 0) {
1054 RDEBUG2("%.*s # unwind to enclosing %s", depth + 1, modcall_spaces,
1055 group_name[entry->unwind]);
1061 entry->c = entry->c->next;
1063 if (entry->c) goto redo;
1073 * @brief Call a module, iteratively, with a local stack, rather than
1074 * recursively. What did Paul Graham say about Lisp...?
1076 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1078 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1081 memset(stack, 0, sizeof(stack));
1084 * Set up the initial stack frame.
1087 stack[0].result = default_component_results[component];
1088 stack[0].priority = 0;
1089 stack[0].unwind = 0;
1092 * Call the main handler.
1094 if (!modcall_recurse(request, component, 0, &stack[0])) {
1095 return RLM_MODULE_FAIL;
1099 * Return the result.
1101 return stack[0].result;
1106 static char const *action2str(int action)
1108 static char buf[32];
1109 if(action==MOD_ACTION_RETURN)
1111 if(action==MOD_ACTION_REJECT)
1113 snprintf(buf, sizeof buf, "%d", action);
1117 /* If you suspect a bug in the parser, you'll want to use these dump
1118 * functions. dump_tree should reproduce a whole tree exactly as it was found
1119 * in radiusd.conf, but in long form (all actions explicitly defined) */
1120 static void dump_mc(modcallable *c, int indent)
1124 if(c->type==MOD_SINGLE) {
1125 modsingle *single = mod_callabletosingle(c);
1126 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1127 single->modinst->name);
1128 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1129 modgroup *g = mod_callabletogroup(c);
1131 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1132 group_name[c->type]);
1133 for(p = g->children;p;p = p->next)
1134 dump_mc(p, indent+1);
1135 } /* else ignore it for now */
1137 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1138 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1139 fr_int2str(mod_rcode_table, i, "<invalid>"),
1140 action2str(c->actions[i]));
1143 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1146 static void dump_tree(rlm_components_t comp, modcallable *c)
1148 DEBUG("[%s]", comp2str[comp]);
1152 #define dump_tree(a, b)
1155 /* These are the default actions. For each component, the group{} block
1156 * behaves like the code from the old module_*() function. redundant{} and
1157 * append{} are based on my guesses of what they will be used for. --Pac. */
1159 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1165 MOD_ACTION_RETURN, /* reject */
1167 MOD_ACTION_RETURN, /* ok */
1168 MOD_ACTION_RETURN, /* handled */
1170 MOD_ACTION_RETURN, /* userlock */
1171 MOD_ACTION_RETURN, /* notfound */
1177 MOD_ACTION_RETURN, /* reject */
1179 MOD_ACTION_RETURN, /* ok */
1180 MOD_ACTION_RETURN, /* handled */
1181 MOD_ACTION_RETURN, /* invalid */
1182 MOD_ACTION_RETURN, /* userlock */
1183 MOD_ACTION_RETURN, /* notfound */
1184 MOD_ACTION_RETURN, /* noop */
1185 MOD_ACTION_RETURN /* updated */
1189 MOD_ACTION_RETURN, /* reject */
1191 MOD_ACTION_RETURN, /* ok */
1192 MOD_ACTION_RETURN, /* handled */
1193 MOD_ACTION_RETURN, /* invalid */
1194 MOD_ACTION_RETURN, /* userlock */
1196 MOD_ACTION_RETURN, /* noop */
1197 MOD_ACTION_RETURN /* updated */
1204 MOD_ACTION_RETURN, /* reject */
1205 MOD_ACTION_RETURN, /* fail */
1207 MOD_ACTION_RETURN, /* handled */
1208 MOD_ACTION_RETURN, /* invalid */
1209 MOD_ACTION_RETURN, /* userlock */
1216 MOD_ACTION_RETURN, /* reject */
1218 MOD_ACTION_RETURN, /* ok */
1219 MOD_ACTION_RETURN, /* handled */
1220 MOD_ACTION_RETURN, /* invalid */
1221 MOD_ACTION_RETURN, /* userlock */
1222 MOD_ACTION_RETURN, /* notfound */
1223 MOD_ACTION_RETURN, /* noop */
1224 MOD_ACTION_RETURN /* updated */
1228 MOD_ACTION_RETURN, /* reject */
1230 MOD_ACTION_RETURN, /* ok */
1231 MOD_ACTION_RETURN, /* handled */
1232 MOD_ACTION_RETURN, /* invalid */
1233 MOD_ACTION_RETURN, /* userlock */
1235 MOD_ACTION_RETURN, /* noop */
1236 MOD_ACTION_RETURN /* updated */
1243 MOD_ACTION_RETURN, /* reject */
1244 MOD_ACTION_RETURN, /* fail */
1246 MOD_ACTION_RETURN, /* handled */
1247 MOD_ACTION_RETURN, /* invalid */
1248 MOD_ACTION_RETURN, /* userlock */
1249 MOD_ACTION_RETURN, /* notfound */
1255 MOD_ACTION_RETURN, /* reject */
1257 MOD_ACTION_RETURN, /* ok */
1258 MOD_ACTION_RETURN, /* handled */
1259 MOD_ACTION_RETURN, /* invalid */
1260 MOD_ACTION_RETURN, /* userlock */
1261 MOD_ACTION_RETURN, /* notfound */
1262 MOD_ACTION_RETURN, /* noop */
1263 MOD_ACTION_RETURN /* updated */
1267 MOD_ACTION_RETURN, /* reject */
1269 MOD_ACTION_RETURN, /* ok */
1270 MOD_ACTION_RETURN, /* handled */
1271 MOD_ACTION_RETURN, /* invalid */
1272 MOD_ACTION_RETURN, /* userlock */
1274 MOD_ACTION_RETURN, /* noop */
1275 MOD_ACTION_RETURN /* updated */
1282 MOD_ACTION_RETURN, /* reject */
1283 MOD_ACTION_RETURN, /* fail */
1285 MOD_ACTION_RETURN, /* handled */
1286 MOD_ACTION_RETURN, /* invalid */
1287 MOD_ACTION_RETURN, /* userlock */
1288 MOD_ACTION_RETURN, /* notfound */
1296 MOD_ACTION_RETURN, /* ok */
1297 MOD_ACTION_RETURN, /* handled */
1306 MOD_ACTION_RETURN, /* reject */
1308 MOD_ACTION_RETURN, /* ok */
1309 MOD_ACTION_RETURN, /* handled */
1310 MOD_ACTION_RETURN, /* invalid */
1311 MOD_ACTION_RETURN, /* userlock */
1313 MOD_ACTION_RETURN, /* noop */
1314 MOD_ACTION_RETURN /* updated */
1321 MOD_ACTION_RETURN, /* reject */
1323 MOD_ACTION_RETURN, /* ok */
1324 MOD_ACTION_RETURN, /* handled */
1325 MOD_ACTION_RETURN, /* invalid */
1326 MOD_ACTION_RETURN, /* userlock */
1327 MOD_ACTION_RETURN, /* notfound */
1328 MOD_ACTION_RETURN, /* noop */
1329 MOD_ACTION_RETURN /* updated */
1333 MOD_ACTION_RETURN, /* reject */
1335 MOD_ACTION_RETURN, /* ok */
1336 MOD_ACTION_RETURN, /* handled */
1337 MOD_ACTION_RETURN, /* invalid */
1338 MOD_ACTION_RETURN, /* userlock */
1339 MOD_ACTION_RETURN, /* notfound */
1340 MOD_ACTION_RETURN, /* noop */
1341 MOD_ACTION_RETURN /* updated */
1345 MOD_ACTION_RETURN, /* reject */
1347 MOD_ACTION_RETURN, /* ok */
1348 MOD_ACTION_RETURN, /* handled */
1349 MOD_ACTION_RETURN, /* invalid */
1350 MOD_ACTION_RETURN, /* userlock */
1351 MOD_ACTION_RETURN, /* notfound */
1352 MOD_ACTION_RETURN, /* noop */
1353 MOD_ACTION_RETURN /* updated */
1360 MOD_ACTION_RETURN, /* reject */
1361 MOD_ACTION_RETURN, /* fail */
1363 MOD_ACTION_RETURN, /* handled */
1364 MOD_ACTION_RETURN, /* invalid */
1365 MOD_ACTION_RETURN, /* userlock */
1372 MOD_ACTION_RETURN, /* reject */
1374 MOD_ACTION_RETURN, /* ok */
1375 MOD_ACTION_RETURN, /* handled */
1376 MOD_ACTION_RETURN, /* invalid */
1377 MOD_ACTION_RETURN, /* userlock */
1378 MOD_ACTION_RETURN, /* notfound */
1379 MOD_ACTION_RETURN, /* noop */
1380 MOD_ACTION_RETURN /* updated */
1384 MOD_ACTION_RETURN, /* reject */
1386 MOD_ACTION_RETURN, /* ok */
1387 MOD_ACTION_RETURN, /* handled */
1388 MOD_ACTION_RETURN, /* invalid */
1389 MOD_ACTION_RETURN, /* userlock */
1391 MOD_ACTION_RETURN, /* noop */
1392 MOD_ACTION_RETURN /* updated */
1399 MOD_ACTION_RETURN, /* reject */
1400 MOD_ACTION_RETURN, /* fail */
1402 MOD_ACTION_RETURN, /* handled */
1403 MOD_ACTION_RETURN, /* invalid */
1404 MOD_ACTION_RETURN, /* userlock */
1411 MOD_ACTION_RETURN, /* reject */
1413 MOD_ACTION_RETURN, /* ok */
1414 MOD_ACTION_RETURN, /* handled */
1415 MOD_ACTION_RETURN, /* invalid */
1416 MOD_ACTION_RETURN, /* userlock */
1417 MOD_ACTION_RETURN, /* notfound */
1418 MOD_ACTION_RETURN, /* noop */
1419 MOD_ACTION_RETURN /* updated */
1423 MOD_ACTION_RETURN, /* reject */
1425 MOD_ACTION_RETURN, /* ok */
1426 MOD_ACTION_RETURN, /* handled */
1427 MOD_ACTION_RETURN, /* invalid */
1428 MOD_ACTION_RETURN, /* userlock */
1430 MOD_ACTION_RETURN, /* noop */
1431 MOD_ACTION_RETURN /* updated */
1438 MOD_ACTION_RETURN, /* reject */
1439 MOD_ACTION_RETURN, /* fail */
1441 MOD_ACTION_RETURN, /* handled */
1442 MOD_ACTION_RETURN, /* invalid */
1443 MOD_ACTION_RETURN, /* userlock */
1450 MOD_ACTION_RETURN, /* reject */
1452 MOD_ACTION_RETURN, /* ok */
1453 MOD_ACTION_RETURN, /* handled */
1454 MOD_ACTION_RETURN, /* invalid */
1455 MOD_ACTION_RETURN, /* userlock */
1456 MOD_ACTION_RETURN, /* notfound */
1457 MOD_ACTION_RETURN, /* noop */
1458 MOD_ACTION_RETURN /* updated */
1462 MOD_ACTION_RETURN, /* reject */
1464 MOD_ACTION_RETURN, /* ok */
1465 MOD_ACTION_RETURN, /* handled */
1466 MOD_ACTION_RETURN, /* invalid */
1467 MOD_ACTION_RETURN, /* userlock */
1469 MOD_ACTION_RETURN, /* noop */
1470 MOD_ACTION_RETURN /* updated */
1479 MOD_ACTION_RETURN, /* reject */
1480 MOD_ACTION_RETURN, /* fail */
1482 MOD_ACTION_RETURN, /* handled */
1483 MOD_ACTION_RETURN, /* invalid */
1484 MOD_ACTION_RETURN, /* userlock */
1491 MOD_ACTION_RETURN, /* reject */
1493 MOD_ACTION_RETURN, /* ok */
1494 MOD_ACTION_RETURN, /* handled */
1495 MOD_ACTION_RETURN, /* invalid */
1496 MOD_ACTION_RETURN, /* userlock */
1497 MOD_ACTION_RETURN, /* notfound */
1498 MOD_ACTION_RETURN, /* noop */
1499 MOD_ACTION_RETURN /* updated */
1503 MOD_ACTION_RETURN, /* reject */
1505 MOD_ACTION_RETURN, /* ok */
1506 MOD_ACTION_RETURN, /* handled */
1507 MOD_ACTION_RETURN, /* invalid */
1508 MOD_ACTION_RETURN, /* userlock */
1510 MOD_ACTION_RETURN, /* noop */
1511 MOD_ACTION_RETURN /* updated */
1518 MOD_ACTION_RETURN, /* reject */
1519 MOD_ACTION_RETURN, /* fail */
1521 MOD_ACTION_RETURN, /* handled */
1522 MOD_ACTION_RETURN, /* invalid */
1523 MOD_ACTION_RETURN, /* userlock */
1530 MOD_ACTION_RETURN, /* reject */
1532 MOD_ACTION_RETURN, /* ok */
1533 MOD_ACTION_RETURN, /* handled */
1534 MOD_ACTION_RETURN, /* invalid */
1535 MOD_ACTION_RETURN, /* userlock */
1536 MOD_ACTION_RETURN, /* notfound */
1537 MOD_ACTION_RETURN, /* noop */
1538 MOD_ACTION_RETURN /* updated */
1542 MOD_ACTION_RETURN, /* reject */
1544 MOD_ACTION_RETURN, /* ok */
1545 MOD_ACTION_RETURN, /* handled */
1546 MOD_ACTION_RETURN, /* invalid */
1547 MOD_ACTION_RETURN, /* userlock */
1549 MOD_ACTION_RETURN, /* noop */
1550 MOD_ACTION_RETURN /* updated */
1558 static modcallable *do_compile_modupdate(modcallable *parent, UNUSED rlm_components_t component,
1559 CONF_SECTION *cs, char const *name2)
1563 modcallable *csingle;
1564 value_pair_map_t *map, *head = NULL;
1568 * This looks at cs->name2 to determine which list to update
1570 rcode = radius_attrmap(cs, &head, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, 128);
1571 if (rcode < 0) return NULL; /* message already printed */
1574 cf_log_err_cs(cs, "'update' sections cannot be empty");
1578 for (map = head, ci = cf_item_find_next(cs, NULL);
1580 map = map->next, ci = cf_item_find_next(cs, ci)) {
1582 * Can't copy an xlat expansion or literal into a list,
1583 * we don't know what type of attribute we'd need
1586 * The only exception is where were using a unary
1589 if ((map->dst->type == VPT_TYPE_LIST) &&
1590 (map->op != T_OP_CMP_FALSE) &&
1591 ((map->src->type == VPT_TYPE_XLAT) || (map->src->type == VPT_TYPE_LITERAL))) {
1592 cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
1598 * If LHS is an attribute, and RHS is a literal, we can
1599 * preparse the information into a VPT_TYPE_DATA.
1601 * Unless it's a unary operator in which case we
1604 if ((map->dst->type == VPT_TYPE_ATTR) && (map->op != T_OP_CMP_FALSE) &&
1605 (map->src->type == VPT_TYPE_LITERAL)) {
1608 cp = cf_itemtopair(ci);
1609 rad_assert(cp != NULL);
1612 * It's a literal string, just copy it.
1613 * Don't escape anything.
1615 if ((map->dst->vpt_da->type == PW_TYPE_STRING) &&
1616 (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
1619 map->src->vpt_value = vpd = talloc_zero(map->src, value_data_t);
1620 rad_assert(vpd != NULL);
1622 vpd->strvalue = talloc_typed_strdup(vpd, map->src->name);
1623 rad_assert(vpd->strvalue != NULL);
1625 map->src->type = VPT_TYPE_DATA;
1626 map->src->vpt_da = map->dst->vpt_da;
1627 map->src->vpt_length = talloc_array_length(vpd->strvalue) - 1;
1629 if (!radius_cast_tmpl(map->src, map->dst->vpt_da)) {
1630 cf_log_err(map->ci, "%s", fr_strerror());
1635 } /* else we can't precompile the data */
1636 } /* loop over the conf_pairs in the update section */
1638 g = rad_malloc(sizeof(*g)); /* never fails */
1639 memset(g, 0, sizeof(*g));
1641 csingle = mod_grouptocallable(g);
1643 csingle->parent = parent;
1644 csingle->next = NULL;
1647 csingle->name = name2;
1651 csingle->type = MOD_UPDATE;
1652 csingle->method = component;
1654 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1655 sizeof(csingle->actions));
1657 g->grouptype = GROUPTYPE_SIMPLE;
1666 static modcallable *do_compile_modswitch(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1671 bool had_seen_default = false;
1672 modcallable *csingle;
1674 value_pair_tmpl_t *vpt;
1676 name2 = cf_section_name2(cs);
1679 "You must specify a variable to switch over for 'switch'");
1683 if (!cf_item_find_next(cs, NULL)) {
1684 cf_log_err_cs(cs, "'switch' statements cannot be empty");
1689 * Create the template. If we fail, AND it's a bare word
1690 * with &Foo-Bar, it MAY be an attribute defined by a
1691 * module. Allow it for now. The pass2 checks below
1694 type = cf_section_name2_type(cs);
1695 vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1696 if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1697 cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
1702 * Otherwise a NULL vpt may refer to an attribute defined
1703 * by a module. That is checked in pass 2.
1707 * Walk through the children of the switch section,
1708 * ensuring that they're all 'case' statements
1710 for (ci=cf_item_find_next(cs, NULL);
1712 ci=cf_item_find_next(cs, ci)) {
1713 CONF_SECTION *subcs;
1716 if (!cf_item_is_section(ci)) {
1717 if (!cf_item_is_pair(ci)) continue;
1719 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1724 subcs = cf_itemtosection(ci); /* can't return NULL */
1725 name1 = cf_section_name1(subcs);
1727 if (strcmp(name1, "case") != 0) {
1728 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1733 name2 = cf_section_name2(subcs);
1734 if (!name2 && !had_seen_default) {
1735 had_seen_default = true;
1739 if (!name2 || (name2[0] == '\0')) {
1740 cf_log_err(ci, "\"case\" sections must have a name");
1746 csingle = do_compile_modgroup(parent, component, cs,
1755 g = mod_callabletogroup(csingle);
1761 static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1765 modcallable *csingle;
1767 value_pair_tmpl_t *vpt;
1769 if (!parent || (parent->type != MOD_SWITCH)) {
1770 cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
1775 * case THING means "match THING"
1776 * case means "match anything"
1778 name2 = cf_section_name2(cs);
1782 type = cf_section_name2_type(cs);
1784 vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1785 if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1786 cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
1791 * Otherwise a NULL vpt may refer to an attribute defined
1792 * by a module. That is checked in pass 2.
1799 csingle= do_compile_modgroup(parent, component, cs,
1809 * The interpretor expects this to be NULL for the
1810 * default case. do_compile_modgroup sets it to name2,
1811 * unless name2 is NULL, in which case it sets it to name1.
1813 csingle->name = name2;
1815 g = mod_callabletogroup(csingle);
1819 * Set all of it's codes to return, so that
1820 * when we pick a 'case' statement, we don't
1821 * fall through to processing the next one.
1823 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1824 csingle->actions[i] = MOD_ACTION_RETURN;
1830 static modcallable *do_compile_modforeach(modcallable *parent,
1831 UNUSED rlm_components_t component, CONF_SECTION *cs)
1835 modcallable *csingle;
1837 value_pair_tmpl_t *vpt;
1839 name2 = cf_section_name2(cs);
1842 "You must specify an attribute to loop over in 'foreach'");
1846 if (!cf_item_find_next(cs, NULL)) {
1847 cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
1852 * Create the template. If we fail, AND it's a bare word
1853 * with &Foo-Bar, it MAY be an attribute defined by a
1854 * module. Allow it for now. The pass2 checks below
1857 type = cf_section_name2_type(cs);
1858 vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1859 if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1860 cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
1864 if (vpt && (vpt->type != VPT_TYPE_ATTR)) {
1865 cf_log_err_cs(cs, "MUST use attribute reference in 'foreach'");
1869 csingle = do_compile_modgroup(parent, component, cs,
1870 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
1878 g = mod_callabletogroup(csingle);
1884 static modcallable *do_compile_modbreak(modcallable *parent,
1885 rlm_components_t component, CONF_ITEM const *ci)
1887 CONF_SECTION const *cs = NULL;
1889 for (cs = cf_item_parent(ci);
1891 cs = cf_item_parent(cf_sectiontoitem(cs))) {
1892 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
1898 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
1902 return do_compile_modgroup(parent, component, NULL,
1903 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
1908 static modcallable *do_compile_modserver(modcallable *parent,
1909 rlm_components_t component, CONF_ITEM *ci,
1914 modcallable *csingle;
1915 CONF_SECTION *subcs;
1918 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
1920 cf_log_err(ci, "Server %s has no %s section",
1921 server, comp2str[component]);
1925 mr = rad_malloc(sizeof(*mr));
1926 memset(mr, 0, sizeof(*mr));
1928 csingle = mod_reftocallable(mr);
1929 csingle->parent = parent;
1930 csingle->next = NULL;
1931 csingle->name = name;
1932 csingle->type = MOD_REFERENCE;
1933 csingle->method = component;
1935 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1936 sizeof(csingle->actions));
1938 mr->ref_name = strdup(server);
1944 static modcallable *do_compile_modxlat(modcallable *parent,
1945 rlm_components_t component, char const *fmt)
1947 modcallable *csingle;
1950 mx = rad_malloc(sizeof(*mx));
1951 memset(mx, 0, sizeof(*mx));
1953 csingle = mod_xlattocallable(mx);
1954 csingle->parent = parent;
1955 csingle->next = NULL;
1956 csingle->name = "expand";
1957 csingle->type = MOD_XLAT;
1958 csingle->method = component;
1960 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1961 sizeof(csingle->actions));
1963 mx->xlat_name = strdup(fmt);
1964 if (fmt[0] != '%') {
1968 strcpy(mx->xlat_name, fmt + 1);
1969 p = strrchr(mx->xlat_name, '`');
1977 * redundant, etc. can refer to modules or groups, but not much else.
1979 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
1983 for (ci=cf_item_find_next(cs, NULL);
1985 ci=cf_item_find_next(cs, ci)) {
1987 * If we're a redundant, etc. group, then the
1988 * intention is to call modules, rather than
1989 * processing logic. These checks aren't
1990 * *strictly* necessary, but they keep the users
1991 * from doing crazy things.
1993 if (cf_item_is_section(ci)) {
1994 CONF_SECTION *subcs = cf_itemtosection(ci);
1995 char const *name1 = cf_section_name1(subcs);
1997 if ((strcmp(name1, "if") == 0) ||
1998 (strcmp(name1, "else") == 0) ||
1999 (strcmp(name1, "elsif") == 0) ||
2000 (strcmp(name1, "update") == 0) ||
2001 (strcmp(name1, "switch") == 0) ||
2002 (strcmp(name1, "case") == 0)) {
2003 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
2010 if (cf_item_is_pair(ci)) {
2011 CONF_PAIR *cp = cf_itemtopair(ci);
2012 if (cf_pair_value(cp) != NULL) {
2014 "Entry with no value is invalid");
2025 * Compile one entry of a module call.
2027 static modcallable *do_compile_modsingle(modcallable *parent,
2028 rlm_components_t component, CONF_ITEM *ci,
2030 char const **modname)
2032 char const *modrefname;
2034 modcallable *csingle;
2035 module_instance_t *this;
2036 CONF_SECTION *cs, *subcs, *modules;
2037 char const *realname;
2039 if (cf_item_is_section(ci)) {
2042 cs = cf_itemtosection(ci);
2043 modrefname = cf_section_name1(cs);
2044 name2 = cf_section_name2(cs);
2045 if (!name2) name2 = "";
2048 * group{}, redundant{}, or append{} may appear
2049 * where a single module instance was expected.
2050 * In that case, we hand it off to
2053 if (strcmp(modrefname, "group") == 0) {
2055 return do_compile_modgroup(parent, component, cs,
2057 grouptype, MOD_GROUP);
2059 } else if (strcmp(modrefname, "redundant") == 0) {
2062 if (!all_children_are_modules(cs, modrefname)) {
2066 return do_compile_modgroup(parent, component, cs,
2067 GROUPTYPE_REDUNDANT,
2068 grouptype, MOD_GROUP);
2070 } else if (strcmp(modrefname, "append") == 0) {
2072 return do_compile_modgroup(parent, component, cs,
2074 grouptype, MOD_GROUP);
2076 } else if (strcmp(modrefname, "load-balance") == 0) {
2079 if (!all_children_are_modules(cs, modrefname)) {
2083 return do_compile_modgroup(parent, component, cs,
2085 grouptype, MOD_LOAD_BALANCE);
2087 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
2090 if (!all_children_are_modules(cs, modrefname)) {
2094 return do_compile_modgroup(parent, component, cs,
2095 GROUPTYPE_REDUNDANT,
2096 grouptype, MOD_REDUNDANT_LOAD_BALANCE);
2099 } else if (strcmp(modrefname, "if") == 0) {
2100 if (!cf_section_name2(cs)) {
2101 cf_log_err(ci, "'if' without condition");
2106 csingle= do_compile_modgroup(parent, component, cs,
2109 if (!csingle) return NULL;
2114 } else if (strcmp(modrefname, "elsif") == 0) {
2116 ((parent->type == MOD_LOAD_BALANCE) ||
2117 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2118 cf_log_err(ci, "'elsif' cannot be used in this section");
2122 if (!cf_section_name2(cs)) {
2123 cf_log_err(ci, "'elsif' without condition");
2128 return do_compile_modgroup(parent, component, cs,
2130 grouptype, MOD_ELSIF);
2132 } else if (strcmp(modrefname, "else") == 0) {
2134 ((parent->type == MOD_LOAD_BALANCE) ||
2135 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2136 cf_log_err(ci, "'else' cannot be used in this section section");
2140 if (cf_section_name2(cs)) {
2141 cf_log_err(ci, "Cannot have conditions on 'else'");
2146 return do_compile_modgroup(parent, component, cs,
2148 grouptype, MOD_ELSE);
2150 } else if (strcmp(modrefname, "update") == 0) {
2153 return do_compile_modupdate(parent, component, cs,
2156 } else if (strcmp(modrefname, "switch") == 0) {
2159 return do_compile_modswitch(parent, component, cs);
2161 } else if (strcmp(modrefname, "case") == 0) {
2164 return do_compile_modcase(parent, component, cs);
2166 } else if (strcmp(modrefname, "foreach") == 0) {
2169 return do_compile_modforeach(parent, component, cs);
2172 } /* else it's something like sql { fail = 1 ...} */
2174 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2178 * Else it's a module reference, with updated return
2183 CONF_PAIR *cp = cf_itemtopair(ci);
2184 modrefname = cf_pair_attr(cp);
2187 * Actions (ok = 1), etc. are orthoganal to just
2188 * about everything else.
2190 if (cf_pair_value(cp) != NULL) {
2191 cf_log_err(ci, "Entry is not a reference to a module");
2195 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2196 (modrefname[0] == '`')) {
2197 return do_compile_modxlat(parent, component,
2202 * See if the module is a virtual one. If so,
2203 * return that, rather than doing anything here.
2206 cs = cf_section_find("instantiate");
2207 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
2210 (cs = cf_section_find("policy")) != NULL) {
2213 snprintf(buffer, sizeof(buffer), "%s.%s",
2214 modrefname, comp2str[component]);
2217 * Prefer name.section, then name.
2219 subcs = cf_section_sub_find_name2(cs, NULL,
2222 subcs = cf_section_sub_find_name2(cs, NULL,
2228 * Allow policies to over-ride module names.
2229 * i.e. the "sql" policy can do some extra things,
2230 * and then call the "sql" module.
2232 for (loop = cf_item_parent(ci);
2234 loop = cf_item_parent(cf_sectiontoitem(loop))) {
2235 if (loop == subcs) {
2242 * redundant foo {} is a single.
2244 if (cf_section_name2(subcs)) {
2245 return do_compile_modsingle(parent,
2247 cf_sectiontoitem(subcs),
2252 * foo {} is a group.
2254 return do_compile_modgroup(parent,
2258 grouptype, MOD_GROUP);
2264 if (strcmp(modrefname, "break") == 0) {
2265 return do_compile_modbreak(parent, component, ci);
2270 * Not a virtual module. It must be a real module.
2272 modules = cf_section_find("modules");
2274 realname = modrefname;
2278 * Try to load the optional module.
2280 if (realname[0] == '-') realname++;
2283 * As of v3, only known modules are in the
2284 * "modules" section.
2286 if (cf_section_sub_find_name2(modules, NULL, realname)) {
2287 this = find_module_instance(modules, realname, 1);
2288 if (!this && (realname != modrefname)) {
2294 * We were asked to MAYBE load it and it
2295 * doesn't exist. Return a soft error.
2297 if (realname != modrefname) {
2298 *modname = modrefname;
2309 * Maybe it's module.method
2311 p = strrchr(modrefname, '.');
2312 if (p) for (i = RLM_COMPONENT_AUTH;
2313 i < RLM_COMPONENT_COUNT;
2315 if (strcmp(p + 1, comp2str[i]) == 0) {
2318 strlcpy(buffer, modrefname, sizeof(buffer));
2319 buffer[p - modrefname] = '\0';
2322 this = find_module_instance(modules, buffer, 1);
2324 !this->entry->module->methods[i]) {
2326 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
2335 * Call a server. This should really be deleted...
2337 if (strncmp(modrefname, "server[", 7) == 0) {
2340 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2341 p = strrchr(buffer, ']');
2342 if (!p || p[1] != '\0' || (p == buffer)) {
2343 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2348 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2350 cf_log_err(ci, "No such server \"%s\".", buffer);
2354 return do_compile_modserver(parent, component, ci,
2355 modrefname, cs, buffer);
2359 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
2364 * We know it's all OK, allocate the structures, and fill
2367 single = rad_malloc(sizeof(*single));
2368 memset(single, 0, sizeof(*single));
2369 csingle = mod_singletocallable(single);
2370 csingle->parent = parent;
2371 csingle->next = NULL;
2372 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2373 memcpy(csingle->actions, defaultactions[component][grouptype],
2374 sizeof csingle->actions);
2375 } else { /* inside Auth-Type has different rules */
2376 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2377 sizeof csingle->actions);
2379 rad_assert(modrefname != NULL);
2380 csingle->name = realname;
2381 csingle->type = MOD_SINGLE;
2382 csingle->method = component;
2385 * Singles can override the actions, virtual modules cannot.
2387 * FIXME: We may want to re-visit how to do this...
2388 * maybe a csingle as a ref?
2390 if (cf_item_is_section(ci)) {
2393 cs = cf_itemtosection(ci);
2394 for (csi=cf_item_find_next(cs, NULL);
2396 csi=cf_item_find_next(cs, csi)) {
2398 if (cf_item_is_section(csi)) {
2399 cf_log_err(csi, "Subsection of module instance call not allowed");
2400 modcallable_free(&csingle);
2404 if (!cf_item_is_pair(csi)) continue;
2406 if (!compile_action(csingle, cf_itemtopair(csi))) {
2407 modcallable_free(&csingle);
2414 * Bail out if the module in question does not supply the
2417 if (!this->entry->module->methods[component]) {
2418 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2419 comp2str[component]);
2420 modcallable_free(&csingle);
2424 single->modinst = this;
2425 *modname = this->entry->module->name;
2429 modcallable *compile_modsingle(modcallable **parent,
2430 rlm_components_t component, CONF_ITEM *ci,
2431 char const **modname)
2438 CONF_SECTION *parentcs;
2440 g = rad_malloc(sizeof *g);
2441 memset(g, 0, sizeof(*g));
2442 g->grouptype = GROUPTYPE_SIMPLE;
2443 c = mod_grouptocallable(g);
2446 defaultactions[component][GROUPTYPE_SIMPLE],
2447 sizeof(c->actions));
2449 parentcs = cf_item_parent(ci);
2450 c->name = cf_section_name2(parentcs);
2452 c->name = cf_section_name1(parentcs);
2455 c->type = MOD_GROUP;
2456 c->method = component;
2459 *parent = mod_grouptocallable(g);
2462 ret = do_compile_modsingle(*parent, component, ci,
2465 dump_tree(component, ret);
2471 * Internal compile group code.
2473 static modcallable *do_compile_modgroup(modcallable *parent,
2474 rlm_components_t component, CONF_SECTION *cs,
2475 int grouptype, int parentgrouptype, int mod_type)
2482 g = rad_malloc(sizeof(*g));
2483 memset(g, 0, sizeof(*g));
2484 g->grouptype = grouptype;
2488 c = mod_grouptocallable(g);
2492 memset(c->actions, 0, sizeof(c->actions));
2494 if (!cs) { /* only for "break" */
2500 * Remember the name for printing, etc.
2502 * FIXME: We may also want to put the names into a
2503 * rbtree, so that groups can reference each other...
2505 c->name = cf_section_name2(cs);
2507 c->name = cf_section_name1(cs);
2508 if ((strcmp(c->name, "group") == 0) ||
2509 (strcmp(c->name, "redundant") == 0)) {
2511 } else if (c->type == MOD_GROUP) {
2512 c->type = MOD_POLICY;
2518 * Do load-time optimizations
2520 if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
2523 rad_assert(parent != NULL);
2525 if (c->type == MOD_IF) {
2526 g->cond = cf_data_find(g->cs, "if");
2527 rad_assert(g->cond != NULL);
2530 if (g->cond->type == COND_TYPE_FALSE) {
2531 INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
2532 group_name[g->mc.type],
2533 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2537 } else if (c->type == MOD_ELSIF) {
2539 g->cond = cf_data_find(g->cs, "if");
2540 rad_assert(g->cond != NULL);
2542 rad_assert(parent != NULL);
2543 p = mod_callabletogroup(parent);
2545 rad_assert(p->tail != NULL);
2547 f = mod_callabletogroup(p->tail);
2548 rad_assert((f->mc.type == MOD_IF) ||
2549 (f->mc.type == MOD_ELSIF));
2552 * If we took the previous condition, we
2553 * don't need to take this one.
2555 * We reset our condition to 'true', so
2556 * that subsequent sections can check
2557 * that they don't need to be executed.
2559 if (f->cond->type == COND_TYPE_TRUE) {
2561 INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
2562 group_name[g->mc.type],
2563 group_name[f->mc.type],
2564 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2571 rad_assert(c->type == MOD_ELSE);
2573 rad_assert(parent != NULL);
2574 p = mod_callabletogroup(parent);
2576 rad_assert(p->tail != NULL);
2578 f = mod_callabletogroup(p->tail);
2579 rad_assert((f->mc.type == MOD_IF) ||
2580 (f->mc.type == MOD_ELSIF));
2583 * If we took the previous condition, we
2584 * don't need to take this one.
2586 if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
2590 * Else we need to compile this section
2596 * Loop over the children of this group.
2598 for (ci=cf_item_find_next(cs, NULL);
2600 ci=cf_item_find_next(cs, ci)) {
2603 * Sections are references to other groups, or
2604 * to modules with updated return codes.
2606 if (cf_item_is_section(ci)) {
2607 char const *junk = NULL;
2608 modcallable *single;
2609 CONF_SECTION *subcs = cf_itemtosection(ci);
2611 single = do_compile_modsingle(c, component, ci,
2614 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2615 cf_section_name1(subcs));
2616 modcallable_free(&c);
2619 add_child(g, single);
2621 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2625 char const *attr, *value;
2626 CONF_PAIR *cp = cf_itemtopair(ci);
2628 attr = cf_pair_attr(cp);
2629 value = cf_pair_value(cp);
2632 * A CONF_PAIR is either a module
2633 * instance with no actions
2637 modcallable *single;
2638 char const *junk = NULL;
2640 single = do_compile_modsingle(c,
2646 if (cf_item_is_pair(ci) &&
2647 cf_pair_attr(cf_itemtopair(ci))[0] == '-') {
2652 "Failed to parse \"%s\" entry.",
2654 modcallable_free(&c);
2657 add_child(g, single);
2660 * Or a module instance with action.
2662 } else if (!compile_action(c, cp)) {
2663 modcallable_free(&c);
2665 } /* else it worked */
2671 * Set the default actions, if they haven't already been
2674 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2675 if (!c->actions[i]) {
2676 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2677 c->actions[i] = defaultactions[component][parentgrouptype][i];
2678 } else { /* inside Auth-Type has different rules */
2679 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2689 if (grouptype != GROUPTYPE_REDUNDANT) break;
2692 case MOD_LOAD_BALANCE:
2693 case MOD_REDUNDANT_LOAD_BALANCE:
2695 cf_log_err_cs(g->cs, "%s sections cannot be empty",
2696 cf_section_name1(g->cs));
2697 modcallable_free(&c);
2703 * FIXME: If there are no children, return NULL?
2705 return mod_grouptocallable(g);
2708 modcallable *compile_modgroup(modcallable *parent,
2709 rlm_components_t component, CONF_SECTION *cs)
2711 modcallable *ret = do_compile_modgroup(parent, component, cs,
2713 GROUPTYPE_SIMPLE, MOD_GROUP);
2715 if (debug_flag > 3) {
2716 modcall_debug(ret, 2);
2722 void add_to_modcallable(modcallable *parent, modcallable *this)
2726 rad_assert(this != NULL);
2727 rad_assert(parent != NULL);
2729 g = mod_callabletogroup(parent);
2734 void modcallable_free(modcallable **pc)
2736 modcallable *c, *loop, *next;
2738 if (!pc || !*pc) return;
2742 if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
2743 modgroup *g = mod_callabletogroup(c);
2745 if (g->children) for (loop = g->children;
2749 modcallable_free(&loop);
2751 talloc_free(g->map);
2759 static char const spaces[] = " ";
2761 static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t **pvpt, bool convert)
2767 value_pair_tmpl_t *vpt;
2771 rad_assert(vpt->type == VPT_TYPE_XLAT);
2773 fmt = talloc_typed_strdup(vpt, vpt->name);
2774 slen = xlat_tokenize(vpt, fmt, &head, &error);
2777 char const *prefix = "";
2778 char const *p = vpt->name;
2779 size_t indent = -slen;
2781 if (indent >= sizeof(spaces)) {
2782 size_t offset = (indent - (sizeof(spaces) - 1)) + (sizeof(spaces) * 0.75);
2789 cf_log_err(ci, "Failed parsing expanded string:");
2790 cf_log_err(ci, "%s%s", prefix, p);
2791 cf_log_err(ci, "%s%.*s^ %s", prefix, (int) indent, spaces, error);
2797 * Convert %{Attribute-Name} to &Attribute-Name
2800 value_pair_tmpl_t *attr;
2802 attr = radius_xlat2tmpl(talloc_parent(vpt), head);
2804 if (cf_item_is_pair(ci)) {
2805 CONF_PAIR *cp = cf_itemtopair(ci);
2807 WARN("%s[%d] Please change %%{%s} to &%s",
2808 cf_pair_filename(cp), cf_pair_lineno(cp),
2809 attr->name, attr->name);
2811 CONF_SECTION *cs = cf_itemtosection(ci);
2813 WARN("%s[%d] Please change %%{%s} to &%s",
2814 cf_section_filename(cs), cf_section_lineno(cs),
2815 attr->name, attr->name);
2824 * Re-write it to be a pre-parsed XLAT structure.
2826 vpt->type = VPT_TYPE_XLAT_STRUCT;
2827 vpt->vpt_xlat = head;
2834 static int _free_compiled_regex(regex_t *preg)
2840 static bool pass2_regex_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
2845 rad_assert(vpt->type == VPT_TYPE_REGEX);
2848 * Expanded at run-time. We can't precompile it.
2850 if (strchr(vpt->name, '%')) return true;
2852 preg = talloc_zero(vpt, regex_t);
2853 talloc_set_destructor(preg, _free_compiled_regex);
2854 if (!preg) return false;
2856 rcode = regcomp(preg, vpt->name, REG_EXTENDED | (vpt->vpt_iflag ? REG_ICASE : 0));
2859 regerror(rcode, preg, buffer, sizeof(buffer));
2861 cf_log_err(ci, "Invalid regular expression %s: %s",
2866 vpt->type = VPT_TYPE_REGEX_STRUCT;
2867 vpt->vpt_preg = preg;
2873 static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
2875 value_pair_map_t *map;
2877 if (c->type == COND_TYPE_EXISTS) {
2878 if (c->data.vpt->type == VPT_TYPE_XLAT) {
2879 return pass2_xlat_compile(c->ci, &c->data.vpt, true);
2882 rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
2885 * FIXME: fix up attribute references, too!
2891 * Maps have a paircompare fixup applied to them.
2892 * Others get ignored.
2894 if (c->pass2_fixup == PASS2_FIXUP_NONE) {
2895 if (c->type == COND_TYPE_MAP) {
2903 map = c->data.map; /* shorter */
2908 * Where "foo" is dynamically defined.
2910 if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
2911 if (!dict_valbyname(map->dst->vpt_da->attr,
2912 map->dst->vpt_da->vendor,
2914 cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
2915 map->dst->vpt_da->name,
2921 * These guys can't have a paircompare fixup applied.
2923 c->pass2_fixup = PASS2_FIXUP_NONE;
2927 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
2928 value_pair_map_t *old;
2929 value_pair_tmpl_t vpt;
2934 * It's still not an attribute. Ignore it.
2936 if (radius_parse_attr(&vpt, map->dst->name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
2937 cf_log_err(old->ci, "Failed parsing condition: %s", fr_strerror());
2938 c->pass2_fixup = PASS2_FIXUP_NONE;
2943 * Re-parse the LHS as an attribute.
2945 map = radius_str2map(c, old->dst->name, T_BARE_WORD, old->op,
2946 old->src->name, T_BARE_WORD,
2947 REQUEST_CURRENT, PAIR_LIST_REQUEST,
2948 REQUEST_CURRENT, PAIR_LIST_REQUEST);
2950 cf_log_err(old->ci, "Failed parsing condition");
2956 c->pass2_fixup = PASS2_FIXUP_NONE;
2961 * Just in case someone adds a new fixup later.
2963 rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
2964 (c->pass2_fixup == PASS2_PAIRCOMPARE));
2969 if (map->dst->type == VPT_TYPE_XLAT) {
2971 * Don't compile the LHS to an attribute
2972 * reference for now. When we do that, we've got
2973 * to check the RHS for type-specific data, and
2974 * parse it to a VPT_TYPE_DATA.
2976 if (!pass2_xlat_compile(map->ci, &map->dst, false)) {
2981 if (map->src->type == VPT_TYPE_XLAT) {
2983 * Convert the RHS to an attribute reference only
2984 * if the LHS is an attribute reference, too.
2986 * We can fix this when the code in evaluate.c
2987 * can handle strings on the LHS, and attributes
2988 * on the RHS. For now, the code in parser.c
2991 if (!pass2_xlat_compile(map->ci, &map->src, (map->dst->type == VPT_TYPE_ATTR))) {
2997 * Convert bare refs to %{Foreach-Variable-N}
2999 if ((map->dst->type == VPT_TYPE_LITERAL) &&
3000 (strncmp(map->dst->name, "Foreach-Variable-", 17) == 0)) {
3002 value_pair_tmpl_t *vpt;
3004 fmt = talloc_asprintf(map->dst, "%%{%s}", map->dst->name);
3005 vpt = radius_str2tmpl(map, fmt, T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
3007 cf_log_err(map->ci, "Failed compiling %s", map->dst->name);
3011 talloc_free(map->dst);
3016 if (map->src->type == VPT_TYPE_REGEX) {
3017 if (!pass2_regex_compile(map->ci, map->src)) {
3021 rad_assert(map->dst->type != VPT_TYPE_REGEX);
3025 * Only attributes can have a paircompare registered, and
3026 * they can only be with the current REQUEST, and only
3027 * with the request pairs.
3029 if ((map->dst->type != VPT_TYPE_ATTR) ||
3030 (map->dst->vpt_request != REQUEST_CURRENT) ||
3031 (map->dst->vpt_list != PAIR_LIST_REQUEST)) {
3035 if (!radius_find_compare(map->dst->vpt_da)) return true;
3037 if (map->src->type == VPT_TYPE_ATTR) {
3038 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
3043 if (map->src->type == VPT_TYPE_REGEX) {
3044 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
3050 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
3055 if (map->op != T_OP_CMP_EQ) {
3056 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
3062 * Mark it as requiring a paircompare() call, instead of
3065 c->pass2_fixup = PASS2_PAIRCOMPARE;
3072 * Compile the RHS of update sections to xlat_exp_t
3074 static bool modcall_pass2_update(modgroup *g)
3076 value_pair_map_t *map;
3078 for (map = g->map; map != NULL; map = map->next) {
3079 if (map->src->type == VPT_TYPE_XLAT) {
3080 rad_assert(map->src->vpt_xlat == NULL);
3083 * FIXME: compile to attribute && handle
3084 * the conversion in radius_map2vp().
3086 if (!pass2_xlat_compile(map->ci, &map->src, false)) {
3091 rad_assert(map->src->type != VPT_TYPE_REGEX);
3099 * Do a second-stage pass on compiling the modules.
3101 bool modcall_pass2(modcallable *mc)
3106 for (this = mc; this != NULL; this = this->next) {
3107 switch (this->type) {
3114 g = mod_callabletogroup(this);
3115 if (g->done_pass2) return true;
3117 if (!modcall_pass2_update(g)) {
3120 g->done_pass2 = true;
3123 case MOD_XLAT: /* @todo: pre-parse xlat's */
3129 break; /* do nothing */
3134 g = mod_callabletogroup(this);
3135 if (g->done_pass2) return true;
3138 * Don't walk over these.
3140 if ((g->cond->type == COND_TYPE_TRUE) ||
3141 (g->cond->type == COND_TYPE_FALSE)) {
3146 * The compilation code takes care of
3147 * simplifying 'true' and 'false'
3148 * conditions. For others, we have to do
3149 * a second pass to parse && compile xlats.
3151 if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
3155 if (!modcall_pass2(g->children)) return false;
3156 g->done_pass2 = true;
3162 g = mod_callabletogroup(this);
3163 if (g->done_pass2) return true;
3166 * We had &Foo-Bar, where Foo-Bar is
3167 * defined by a module.
3170 rad_assert(this->name != NULL);
3171 rad_assert(this->name[0] == '&');
3172 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3177 * Statically compile xlats
3179 if (g->vpt->type == VPT_TYPE_XLAT) goto do_case_xlat;
3182 * We may have: switch Foo-Bar {
3184 * where Foo-Bar is an attribute defined
3185 * by a module. Since there's no leading
3186 * &, it's parsed as a literal. But if
3187 * we can parse it as an attribute,
3188 * switch to using that.
3190 if (g->vpt->type == VPT_TYPE_LITERAL) {
3191 value_pair_tmpl_t *vpt;
3193 vpt = radius_str2tmpl(g->cs, this->name,
3194 cf_section_name2_type(g->cs),
3195 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3196 if (vpt->type == VPT_TYPE_ATTR) {
3197 talloc_free(g->vpt);
3203 * Warn about old-style configuration.
3205 * DEPRECATED: switch User-Name { ...
3206 * ALLOWED : switch &User-Name { ...
3208 if ((g->vpt->type == VPT_TYPE_ATTR) &&
3209 (this->name[0] != '&')) {
3210 WARN("%s[%d]: Please change %s to &%s",
3211 cf_section_filename(g->cs),
3212 cf_section_lineno(g->cs),
3213 this->name, this->name);
3216 if (!modcall_pass2(g->children)) return false;
3217 g->done_pass2 = true;
3221 g = mod_callabletogroup(this);
3222 if (g->done_pass2) return true;
3226 * The statement may refer to an
3227 * attribute which doesn't exist until
3228 * all of the modules have been loaded.
3229 * Check for that now.
3231 if (!g->vpt && this->name &&
3232 (this->name[0] == '&') &&
3233 (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
3234 g->vpt = radius_str2tmpl(g->cs, this->name,
3235 cf_section_name2_type(g->cs),
3236 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3238 cf_log_err_cs(g->cs, "Syntax error in '%s': %s",
3239 this->name, fr_strerror());
3245 * Do type-specific checks on the case statement
3247 if (g->vpt && (g->vpt->type == VPT_TYPE_LITERAL)) {
3250 rad_assert(this->parent != NULL);
3251 rad_assert(this->parent->type == MOD_SWITCH);
3253 f = mod_callabletogroup(mc->parent);
3254 rad_assert(f->vpt != NULL);
3257 * We're switching over an
3258 * attribute. Check that the
3261 if (f->vpt->type == VPT_TYPE_ATTR) {
3262 rad_assert(f->vpt->vpt_da != NULL);
3264 if (!radius_cast_tmpl(g->vpt, f->vpt->vpt_da)) {
3265 cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
3274 * Compile and sanity check xlat
3278 (g->vpt->type == VPT_TYPE_XLAT) &&
3279 (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3284 if (!modcall_pass2(g->children)) return false;
3285 g->done_pass2 = true;
3289 g = mod_callabletogroup(this);
3290 if (g->done_pass2) return true;
3293 * Already parsed, handle the children.
3295 if (g->vpt) goto check_children;
3298 * We had &Foo-Bar, where Foo-Bar is
3299 * defined by a module.
3301 rad_assert(this->name != NULL);
3302 rad_assert(this->name[0] == '&');
3303 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3306 * The statement may refer to an
3307 * attribute which doesn't exist until
3308 * all of the modules have been loaded.
3309 * Check for that now.
3311 g->vpt = radius_str2tmpl(g->cs, this->name,
3312 cf_section_name2_type(g->cs),
3313 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3315 cf_log_err_cs(g->cs, "Syntax error in '%s': %s",
3316 this->name, fr_strerror());
3321 rad_assert(g->vpt->type == VPT_TYPE_ATTR);
3322 if (g->vpt->vpt_num != NUM_ANY) {
3323 cf_log_err_cs(g->cs, "MUST NOT use array references in 'foreach'");
3326 if (!modcall_pass2(g->children)) return false;
3327 g->done_pass2 = true;
3336 case MOD_LOAD_BALANCE:
3337 case MOD_REDUNDANT_LOAD_BALANCE:
3338 g = mod_callabletogroup(this);
3339 if (g->done_pass2) return true;
3340 if (!modcall_pass2(g->children)) return false;
3341 g->done_pass2 = true;
3349 void modcall_debug(modcallable *mc, int depth)
3353 value_pair_map_t *map;
3357 for (this = mc; this != NULL; this = this->next) {
3358 switch (this->type) {
3363 modsingle *single = mod_callabletosingle(this);
3365 DEBUG("%.*s%s", depth, modcall_spaces,
3366 single->modinst->name);
3372 g = mod_callabletogroup(this);
3373 DEBUG("%.*s%s {", depth, modcall_spaces,
3374 group_name[this->type]);
3376 for (map = g->map; map != NULL; map = map->next) {
3377 radius_map2str(buffer, sizeof(buffer), map);
3378 DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
3381 DEBUG("%.*s}", depth, modcall_spaces);
3385 g = mod_callabletogroup(this);
3386 DEBUG("%.*s%s {", depth, modcall_spaces,
3387 group_name[this->type]);
3388 modcall_debug(g->children, depth + 1);
3389 DEBUG("%.*s}", depth, modcall_spaces);
3394 g = mod_callabletogroup(this);
3395 fr_cond_sprint(buffer, sizeof(buffer), g->cond);
3396 DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
3397 group_name[this->type], buffer);
3398 modcall_debug(g->children, depth + 1);
3399 DEBUG("%.*s}", depth, modcall_spaces);
3404 g = mod_callabletogroup(this);
3405 radius_tmpl2str(buffer, sizeof(buffer), g->vpt);
3406 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3407 group_name[this->type], buffer);
3408 modcall_debug(g->children, depth + 1);
3409 DEBUG("%.*s}", depth, modcall_spaces);
3414 g = mod_callabletogroup(this);
3415 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3416 group_name[this->type], this->name);
3417 modcall_debug(g->children, depth + 1);
3418 DEBUG("%.*s}", depth, modcall_spaces);
3422 DEBUG("%.*sbreak", depth, modcall_spaces);
3427 g = mod_callabletogroup(this);
3428 name1 = cf_section_name1(g->cs);
3429 if (strcmp(name1, "group") == 0) {
3430 DEBUG("%.*s%s {", depth, modcall_spaces,
3431 group_name[this->type]);
3433 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3434 name1, cf_section_name2(g->cs));
3436 modcall_debug(g->children, depth + 1);
3437 DEBUG("%.*s}", depth, modcall_spaces);
3441 case MOD_LOAD_BALANCE:
3442 case MOD_REDUNDANT_LOAD_BALANCE:
3443 g = mod_callabletogroup(this);
3444 DEBUG("%.*s%s {", depth, modcall_spaces,
3445 group_name[this->type]);
3446 modcall_debug(g->children, depth + 1);
3447 DEBUG("%.*s}", depth, modcall_spaces);