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;
76 value_pair_map_t *map; /* update */
77 fr_cond_t *cond; /* if/elsif */
82 module_instance_t *modinst;
98 static const FR_NAME_NUMBER grouptype_table[] = {
99 { "", GROUPTYPE_SIMPLE },
100 { "redundant ", GROUPTYPE_REDUNDANT },
101 { "append ", GROUPTYPE_APPEND },
106 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
107 * so we often want to go back and forth between them. */
108 static modsingle *mod_callabletosingle(modcallable *p)
110 rad_assert(p->type==MOD_SINGLE);
111 return (modsingle *)p;
113 static modgroup *mod_callabletogroup(modcallable *p)
115 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
117 return (modgroup *)p;
119 static modcallable *mod_singletocallable(modsingle *p)
121 return (modcallable *)p;
123 static modcallable *mod_grouptocallable(modgroup *p)
125 return (modcallable *)p;
128 static modref *mod_callabletoref(modcallable *p)
130 rad_assert(p->type==MOD_REFERENCE);
133 static modcallable *mod_reftocallable(modref *p)
135 return (modcallable *)p;
138 static modxlat *mod_callabletoxlat(modcallable *p)
140 rad_assert(p->type==MOD_XLAT);
143 static modcallable *mod_xlattocallable(modxlat *p)
145 return (modcallable *)p;
148 /* modgroups are grown by adding a modcallable to the end */
149 /* FIXME: This is O(N^2) */
150 static void add_child(modgroup *g, modcallable *c)
152 modcallable **head = &g->children;
153 modcallable *node = *head;
154 modcallable **last = head;
163 rad_assert(c->next == NULL);
165 c->parent = mod_grouptocallable(g);
168 /* Here's where we recognize all of our keywords: first the rcodes, then the
170 const FR_NAME_NUMBER mod_rcode_table[] = {
171 { "reject", RLM_MODULE_REJECT },
172 { "fail", RLM_MODULE_FAIL },
173 { "ok", RLM_MODULE_OK },
174 { "handled", RLM_MODULE_HANDLED },
175 { "invalid", RLM_MODULE_INVALID },
176 { "userlock", RLM_MODULE_USERLOCK },
177 { "notfound", RLM_MODULE_NOTFOUND },
178 { "noop", RLM_MODULE_NOOP },
179 { "updated", RLM_MODULE_UPDATED },
185 * Compile action && rcode for later use.
187 static int compile_action(modcallable *c, CONF_PAIR *cp)
190 char const *attr, *value;
192 attr = cf_pair_attr(cp);
193 value = cf_pair_value(cp);
194 if (!value) return 0;
196 if (!strcasecmp(value, "return"))
197 action = MOD_ACTION_RETURN;
199 else if (!strcasecmp(value, "break"))
200 action = MOD_ACTION_RETURN;
202 else if (!strcasecmp(value, "reject"))
203 action = MOD_ACTION_REJECT;
205 else if (strspn(value, "0123456789")==strlen(value)) {
206 action = atoi(value);
209 * Don't allow priority zero, for future use.
211 if (action == 0) return 0;
213 cf_log_err_cp(cp, "Unknown action '%s'.\n",
218 if (strcasecmp(attr, "default") != 0) {
221 rcode = fr_str2int(mod_rcode_table, attr, -1);
224 "Unknown module rcode '%s'.\n",
228 c->actions[rcode] = action;
230 } else { /* set all unset values to the default */
233 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
234 if (!c->actions[i]) c->actions[i] = action;
241 /* Some short names for debugging output */
242 static char const * const comp2str[] = {
258 #ifdef HAVE_PTHREAD_H
260 * Lock the mutex for the module
262 static void safe_lock(module_instance_t *instance)
265 pthread_mutex_lock(instance->mutex);
269 * Unlock the mutex for the module
271 static void safe_unlock(module_instance_t *instance)
274 pthread_mutex_unlock(instance->mutex);
278 * No threads: these functions become NULL's.
280 #define safe_lock(foo)
281 #define safe_unlock(foo)
284 static rlm_rcode_t call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
286 rlm_rcode_t myresult;
289 rad_assert(request != NULL);
292 * If the request should stop, refuse to do anything.
294 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
295 if (blocked) return RLM_MODULE_NOOP;
297 RDEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
298 comp2str[component], sp->modinst->name,
299 sp->modinst->entry->name, request->number);
301 if (sp->modinst->force) {
302 myresult = sp->modinst->code;
306 safe_lock(sp->modinst);
309 * For logging unresponsive children.
311 request->module = sp->modinst->name;
313 myresult = sp->modinst->entry->module->methods[component](
314 sp->modinst->insthandle, request);
316 request->module = "";
317 safe_unlock(sp->modinst);
320 * Wasn't blocked, and now is. Complain!
322 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
324 RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
328 RDEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
329 comp2str[component], sp->modinst->name,
330 sp->modinst->entry->name, request->number);
335 static int default_component_results[RLM_COMPONENT_COUNT] = {
336 RLM_MODULE_REJECT, /* AUTH */
337 RLM_MODULE_NOTFOUND, /* AUTZ */
338 RLM_MODULE_NOOP, /* PREACCT */
339 RLM_MODULE_NOOP, /* ACCT */
340 RLM_MODULE_FAIL, /* SESS */
341 RLM_MODULE_NOOP, /* PRE_PROXY */
342 RLM_MODULE_NOOP, /* POST_PROXY */
343 RLM_MODULE_NOOP /* POST_AUTH */
346 RLM_MODULE_NOOP, /* RECV_COA_TYPE */
347 RLM_MODULE_NOOP /* SEND_COA_TYPE */
352 static char const *group_name[] = {
356 "load-balance group",
357 "redundant-load-balance group",
373 static char const *modcall_spaces = " ";
375 #define MODCALL_STACK_MAX (32)
378 * Don't call the modules recursively. Instead, do them
379 * iteratively, and manage the call stack ourselves.
381 typedef struct modcall_stack_entry_t {
384 int unwind; /* unwind to this one if it exists */
386 } modcall_stack_entry_t;
389 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
390 modcall_stack_entry_t *entry);
393 * Call a child of a block.
395 static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
396 modcall_stack_entry_t *entry, modcallable *c,
399 modcall_stack_entry_t *next;
401 if (depth >= MODCALL_STACK_MAX) {
402 ERROR("Internal sanity check failed: module stack is too deep");
407 * Initialize the childs stack frame.
411 next->result = entry->result;
415 if (!modcall_recurse(request, component,
417 *result = RLM_MODULE_FAIL;
422 * Unwind back up the stack
424 if (next->unwind != 0) {
425 entry->unwind = next->unwind;
428 *result = next->result;
434 * Interpret the various types of blocks.
436 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
437 modcall_stack_entry_t *entry)
439 bool if_taken, was_if;
444 was_if = if_taken = false;
445 result = RLM_MODULE_UNKNOWN;
452 * Nothing more to do. Return the code and priority
453 * which was set by the caller.
458 * We've been asked to stop. Do so.
460 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
462 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
463 entry->result = RLM_MODULE_FAIL;
464 entry->priority = 9999;
470 * Handle "if" conditions.
472 if (c->type == MOD_IF) {
477 g = mod_callabletogroup(c);
478 rad_assert(g->cond != NULL);
480 RDEBUG2("%.*s %s %s", depth + 1, modcall_spaces,
481 group_name[c->type], c->name);
483 condition = radius_evaluate_cond(request, result, 0, g->cond);
486 REDEBUG("Failed retrieving values required to evaluate condition");
488 RDEBUG2("%.*s %s %s -> %s", depth + 1, modcall_spaces,
490 c->name, condition ? "TRUE" : "FALSE");
494 * Didn't pass. Remember that.
503 * We took the "if". Go recurse into its' children.
511 * "else" if the previous "if" was taken.
512 * "if" if the previous if wasn't taken.
514 if (c->type == MOD_ELSIF) {
515 if (!was_if) goto elsif_error;
518 * Like MOD_ELSE, but allow for a later "else"
521 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
522 depth + 1, modcall_spaces,
523 group_name[c->type], request->number);
530 * Check the "if" condition.
536 * "else" for a preceding "if".
538 if (c->type == MOD_ELSE) {
539 if (!was_if) { /* error */
541 RDEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
542 depth + 1, modcall_spaces,
543 group_name[c->type], request->number);
548 RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
549 depth + 1, modcall_spaces,
550 group_name[c->type], request->number);
557 * We need to process it. Go do that.
565 * We're no longer processing if/else/elsif. Reset the
566 * trackers for those conditions.
570 #endif /* WITH_UNLANG */
572 if (c->type == MOD_SINGLE) {
576 * Process a stand-alone child, and fall through
577 * to dealing with it's parent.
579 sp = mod_callabletosingle(c);
581 result = call_modsingle(c->method, sp, request);
582 RDEBUG2("%.*s[%s] = %s", depth + 1, modcall_spaces, c->name ? c->name : "",
583 fr_int2str(mod_rcode_table, result, "<invalid>"));
584 goto calculate_result;
589 * Update attribute(s)
591 if (c->type == MOD_UPDATE) {
593 modgroup *g = mod_callabletogroup(c);
594 value_pair_map_t *map;
597 MOD_LOG_OPEN_BRACE("update");
598 for (map = g->map; map != NULL; map = map->next) {
599 rcode = radius_map2request(request, map, "update", radius_map2vp, NULL);
601 result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
602 MOD_LOG_CLOSE_BRACE();
603 goto calculate_result;
607 result = RLM_MODULE_NOOP;
608 MOD_LOG_CLOSE_BRACE();
609 goto calculate_result;
613 * Loop over a set of attributes.
615 if (c->type == MOD_FOREACH) {
616 int i, foreach_depth = -1;
618 modcall_stack_entry_t *next = NULL;
620 modgroup *g = mod_callabletogroup(c);
622 if (depth >= MODCALL_STACK_MAX) {
623 ERROR("Internal sanity check failed: module stack is too deep");
628 * Figure out how deep we are in nesting by looking at request_data
631 for (i = 0; i < 8; i++) {
632 if (!request_data_reference(request,
639 if (foreach_depth < 0) {
640 REDEBUG("foreach Nesting too deep!");
641 result = RLM_MODULE_FAIL;
642 goto calculate_result;
645 if (radius_get_vp(&vp, request, c->name) < 0) {
646 RDEBUG("Unknown attribute \"%s\"", c->name);
647 result = RLM_MODULE_FAIL;
648 goto calculate_result;
651 if (!vp) { /* nothing to loop over */
652 MOD_LOG_OPEN_BRACE("foreach");
653 result = RLM_MODULE_NOOP;
654 MOD_LOG_CLOSE_BRACE();
655 goto calculate_result;
658 RDEBUG2("%.*sforeach %s ", depth + 1, modcall_spaces,
661 fr_cursor_init(&cursor, &vp);
662 /* Prime the cursor. */
663 cursor.found = cursor.current;
665 VALUE_PAIR *copy = NULL, **copy_p;
668 if (fr_debug_flag >= 2) {
671 vp_prints_value(buffer, sizeof(buffer), vp, '"');
672 RDEBUG2("%.*s # Foreach-Variable-%d = %s", depth + 1,
673 modcall_spaces, foreach_depth, buffer);
678 * Copy only the one VP we care about.
680 copy = paircopyvp(request, vp);
684 * @fixme: The old code freed copy on
685 * request_data_add or request_data_get.
686 * There's no way to easily do that now.
687 * The foreach code should be audited for
688 * possible memory leaks, though it's not
689 * a huge priority as any leaked memory
690 * will be freed on request free.
692 request_data_add(request, radius_get_vp, foreach_depth, copy_p, false);
695 * Initialize the childs stack frame.
698 next->c = g->children;
699 next->result = entry->result;
703 if (!modcall_recurse(request, component, depth + 1, next)) {
704 request_data_get(request, radius_get_vp, foreach_depth);
709 vp = fr_cursor_next_by_num(&cursor, vp->da->attr, vp->da->vendor, TAG_ANY);
712 * Delete the cached attribute, if it exists.
715 request_data_get(request, radius_get_vp, foreach_depth);
722 * If we've been told to stop processing
725 if (entry->unwind == MOD_FOREACH) {
729 } /* loop over VPs */
731 result = next->result;
732 priority = next->priority;
733 MOD_LOG_CLOSE_BRACE();
734 goto calculate_result;
738 * Break out of a "foreach" loop.
740 if (c->type == MOD_BREAK) {
744 for (i = 8; i >= 0; i--) {
745 copy_p = request_data_get(request, radius_get_vp, i);
747 RDEBUG2("%.*s # break Foreach-Variable-%d", depth + 1,
755 * Leave result / priority on the stack, and stop processing the section.
757 entry->unwind = MOD_FOREACH;
760 #endif /* WITH_PROXY */
763 * Child is a group that has children of it's own.
765 if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
767 || (c->type == MOD_CASE)
775 g = mod_callabletogroup(c);
778 * This should really have been caught in the
779 * compiler, and the node never generated. But
780 * doing that requires changing it's API so that
781 * it returns a flag instead of the compiled
785 RDEBUG2("%.*s%s %s { ... } # empty sub-section is ignored",
786 depth + 1, modcall_spaces, cf_section_name1(g->cs), c->name);
790 MOD_LOG_OPEN_BRACE(cf_section_name1(g->cs));
791 modcall_child(request, component,
792 depth + 1, entry, g->children,
794 MOD_LOG_CLOSE_BRACE();
795 goto calculate_result;
799 if (c->type == MOD_SWITCH) {
800 modcallable *this, *found, *null_case;
804 MOD_LOG_OPEN_BRACE("switch");
807 * If there's no %, it refers to an attribute.
808 * Otherwise, expand it.
810 if (!strchr(c->name, '%')) {
811 VALUE_PAIR *vp = NULL;
813 radius_get_vp(&vp, request, c->name);
815 vp_prints_value(buffer,
822 radius_xlat(buffer, sizeof(buffer),
823 request, c->name, NULL, NULL);
827 * Find either the exact matching name, or the
828 * "case {...}" statement.
830 g = mod_callabletogroup(c);
831 null_case = found = NULL;
832 for (this = g->children; this; this = this->next) {
834 if (!null_case) null_case = this;
837 if (strcmp(buffer, this->name) == 0) {
843 if (!found) found = null_case;
845 MOD_LOG_OPEN_BRACE(group_name[c->type]);
846 modcall_child(request, component,
847 depth + 1, entry, found,
849 MOD_LOG_CLOSE_BRACE();
850 goto calculate_result;
854 if ((c->type == MOD_LOAD_BALANCE) ||
855 (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
857 modcallable *this, *found;
860 MOD_LOG_OPEN_BRACE("load-balance");
862 g = mod_callabletogroup(c);
864 for (this = g->children; this; this = this->next) {
872 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
877 MOD_LOG_OPEN_BRACE(group_name[c->type]);
879 if (c->type == MOD_LOAD_BALANCE) {
880 modcall_child(request, component,
881 depth + 1, entry, found,
888 * Loop over all children in this
889 * section. If we get FAIL, then
890 * continue. Otherwise, stop.
892 for (i = 1; i < count; i++) {
893 modcall_child(request, component,
894 depth + 1, entry, found,
896 if (c->actions[result] == MOD_ACTION_RETURN) {
902 MOD_LOG_CLOSE_BRACE();
903 goto calculate_result;
904 } /* MOD_LOAD_BALANCE */
907 * Reference another virtual server.
909 * This should really be deleted, and replaced with a
910 * more abstracted / functional version.
912 if (c->type == MOD_REFERENCE) {
913 modref *mr = mod_callabletoref(c);
914 char const *server = request->server;
916 if (server == mr->ref_name) {
917 RWDEBUG("Suppressing recursive call to server %s", server);
921 request->server = mr->ref_name;
922 RDEBUG("server %s { # nested call", mr->ref_name);
923 result = indexed_modcall(component, 0, request);
924 RDEBUG("} # server %s with nested call", mr->ref_name);
925 request->server = server;
926 goto calculate_result;
927 } /* MOD_REFERENCE */
930 * xlat a string without doing anything else
932 * This should really be deleted, and replaced with a
933 * more abstracted / functional version.
935 if (c->type == MOD_XLAT) {
936 modxlat *mx = mod_callabletoxlat(c);
940 radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
942 RDEBUG("`%s`", mx->xlat_name);
943 radius_exec_program(request, mx->xlat_name, false, true, NULL, 0,
944 EXEC_TIMEOUT, request->packet->vps, NULL);
951 * Add new module types here.
956 RDEBUG("(%s, %d) ? (%s, %d)",
957 fr_int2str(mod_rcode_table, result, "<invalid>"),
959 fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
964 rad_assert(result != RLM_MODULE_UNKNOWN);
967 * The child's action says return. Do so.
969 if ((c->actions[result] == MOD_ACTION_RETURN) &&
971 entry->result = result;
976 * If "reject", break out of the loop and return
979 if (c->actions[result] == MOD_ACTION_REJECT) {
980 entry->result = RLM_MODULE_REJECT;
985 * The array holds a default priority for this return
986 * code. Grab it in preference to any unset priority.
989 priority = c->actions[result];
993 * We're higher than any previous priority, remember this
994 * return code and priority.
996 if (priority > entry->priority) {
997 entry->result = result;
998 entry->priority = priority;
1003 * If we're processing a "case" statement, we return once
1004 * it's done, rather than going to the next "case" statement.
1006 if (c->type == MOD_CASE) return true;
1010 * If we've been told to stop processing
1013 if (entry->unwind != 0) {
1014 RDEBUG2("%.*s # unwind to enclosing %s", depth + 1, modcall_spaces,
1015 group_name[entry->unwind]);
1021 entry->c = entry->c->next;
1023 if (entry->c) goto redo;
1033 * @brief Call a module, iteratively, with a local stack, rather than
1034 * recursively. What did Paul Graham say about Lisp...?
1036 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1038 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1041 * Set up the initial stack frame.
1044 stack[0].result = default_component_results[component];
1045 stack[0].priority = 0;
1046 stack[0].unwind = 0;
1049 * Call the main handler.
1051 if (!modcall_recurse(request, component, 0, &stack[0])) {
1052 return RLM_MODULE_FAIL;
1056 * Return the result.
1058 return stack[0].result;
1063 static char const *action2str(int action)
1065 static char buf[32];
1066 if(action==MOD_ACTION_RETURN)
1068 if(action==MOD_ACTION_REJECT)
1070 snprintf(buf, sizeof buf, "%d", action);
1074 /* If you suspect a bug in the parser, you'll want to use these dump
1075 * functions. dump_tree should reproduce a whole tree exactly as it was found
1076 * in radiusd.conf, but in long form (all actions explicitly defined) */
1077 static void dump_mc(modcallable *c, int indent)
1081 if(c->type==MOD_SINGLE) {
1082 modsingle *single = mod_callabletosingle(c);
1083 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1084 single->modinst->name);
1085 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1086 modgroup *g = mod_callabletogroup(c);
1088 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1089 group_name[c->type]);
1090 for(p = g->children;p;p = p->next)
1091 dump_mc(p, indent+1);
1092 } /* else ignore it for now */
1094 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1095 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1096 fr_int2str(mod_rcode_table, i, "<invalid>"),
1097 action2str(c->actions[i]));
1100 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1103 static void dump_tree(rlm_components_t comp, modcallable *c)
1105 DEBUG("[%s]", comp2str[comp]);
1109 #define dump_tree(a, b)
1112 /* These are the default actions. For each component, the group{} block
1113 * behaves like the code from the old module_*() function. redundant{} and
1114 * append{} are based on my guesses of what they will be used for. --Pac. */
1116 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1122 MOD_ACTION_RETURN, /* reject */
1124 MOD_ACTION_RETURN, /* ok */
1125 MOD_ACTION_RETURN, /* handled */
1127 MOD_ACTION_RETURN, /* userlock */
1128 MOD_ACTION_RETURN, /* notfound */
1134 MOD_ACTION_RETURN, /* reject */
1136 MOD_ACTION_RETURN, /* ok */
1137 MOD_ACTION_RETURN, /* handled */
1138 MOD_ACTION_RETURN, /* invalid */
1139 MOD_ACTION_RETURN, /* userlock */
1140 MOD_ACTION_RETURN, /* notfound */
1141 MOD_ACTION_RETURN, /* noop */
1142 MOD_ACTION_RETURN /* updated */
1146 MOD_ACTION_RETURN, /* reject */
1148 MOD_ACTION_RETURN, /* ok */
1149 MOD_ACTION_RETURN, /* handled */
1150 MOD_ACTION_RETURN, /* invalid */
1151 MOD_ACTION_RETURN, /* userlock */
1153 MOD_ACTION_RETURN, /* noop */
1154 MOD_ACTION_RETURN /* updated */
1161 MOD_ACTION_RETURN, /* reject */
1162 MOD_ACTION_RETURN, /* fail */
1164 MOD_ACTION_RETURN, /* handled */
1165 MOD_ACTION_RETURN, /* invalid */
1166 MOD_ACTION_RETURN, /* userlock */
1173 MOD_ACTION_RETURN, /* reject */
1175 MOD_ACTION_RETURN, /* ok */
1176 MOD_ACTION_RETURN, /* handled */
1177 MOD_ACTION_RETURN, /* invalid */
1178 MOD_ACTION_RETURN, /* userlock */
1179 MOD_ACTION_RETURN, /* notfound */
1180 MOD_ACTION_RETURN, /* noop */
1181 MOD_ACTION_RETURN /* updated */
1185 MOD_ACTION_RETURN, /* reject */
1187 MOD_ACTION_RETURN, /* ok */
1188 MOD_ACTION_RETURN, /* handled */
1189 MOD_ACTION_RETURN, /* invalid */
1190 MOD_ACTION_RETURN, /* userlock */
1192 MOD_ACTION_RETURN, /* noop */
1193 MOD_ACTION_RETURN /* updated */
1200 MOD_ACTION_RETURN, /* reject */
1201 MOD_ACTION_RETURN, /* fail */
1203 MOD_ACTION_RETURN, /* handled */
1204 MOD_ACTION_RETURN, /* invalid */
1205 MOD_ACTION_RETURN, /* userlock */
1206 MOD_ACTION_RETURN, /* notfound */
1212 MOD_ACTION_RETURN, /* reject */
1214 MOD_ACTION_RETURN, /* ok */
1215 MOD_ACTION_RETURN, /* handled */
1216 MOD_ACTION_RETURN, /* invalid */
1217 MOD_ACTION_RETURN, /* userlock */
1218 MOD_ACTION_RETURN, /* notfound */
1219 MOD_ACTION_RETURN, /* noop */
1220 MOD_ACTION_RETURN /* updated */
1224 MOD_ACTION_RETURN, /* reject */
1226 MOD_ACTION_RETURN, /* ok */
1227 MOD_ACTION_RETURN, /* handled */
1228 MOD_ACTION_RETURN, /* invalid */
1229 MOD_ACTION_RETURN, /* userlock */
1231 MOD_ACTION_RETURN, /* noop */
1232 MOD_ACTION_RETURN /* updated */
1239 MOD_ACTION_RETURN, /* reject */
1240 MOD_ACTION_RETURN, /* fail */
1242 MOD_ACTION_RETURN, /* handled */
1243 MOD_ACTION_RETURN, /* invalid */
1244 MOD_ACTION_RETURN, /* userlock */
1245 MOD_ACTION_RETURN, /* notfound */
1253 MOD_ACTION_RETURN, /* ok */
1254 MOD_ACTION_RETURN, /* handled */
1263 MOD_ACTION_RETURN, /* reject */
1265 MOD_ACTION_RETURN, /* ok */
1266 MOD_ACTION_RETURN, /* handled */
1267 MOD_ACTION_RETURN, /* invalid */
1268 MOD_ACTION_RETURN, /* userlock */
1270 MOD_ACTION_RETURN, /* noop */
1271 MOD_ACTION_RETURN /* updated */
1278 MOD_ACTION_RETURN, /* reject */
1280 MOD_ACTION_RETURN, /* ok */
1281 MOD_ACTION_RETURN, /* handled */
1282 MOD_ACTION_RETURN, /* invalid */
1283 MOD_ACTION_RETURN, /* userlock */
1284 MOD_ACTION_RETURN, /* notfound */
1285 MOD_ACTION_RETURN, /* noop */
1286 MOD_ACTION_RETURN /* updated */
1290 MOD_ACTION_RETURN, /* reject */
1292 MOD_ACTION_RETURN, /* ok */
1293 MOD_ACTION_RETURN, /* handled */
1294 MOD_ACTION_RETURN, /* invalid */
1295 MOD_ACTION_RETURN, /* userlock */
1296 MOD_ACTION_RETURN, /* notfound */
1297 MOD_ACTION_RETURN, /* noop */
1298 MOD_ACTION_RETURN /* updated */
1302 MOD_ACTION_RETURN, /* reject */
1304 MOD_ACTION_RETURN, /* ok */
1305 MOD_ACTION_RETURN, /* handled */
1306 MOD_ACTION_RETURN, /* invalid */
1307 MOD_ACTION_RETURN, /* userlock */
1308 MOD_ACTION_RETURN, /* notfound */
1309 MOD_ACTION_RETURN, /* noop */
1310 MOD_ACTION_RETURN /* updated */
1317 MOD_ACTION_RETURN, /* reject */
1318 MOD_ACTION_RETURN, /* fail */
1320 MOD_ACTION_RETURN, /* handled */
1321 MOD_ACTION_RETURN, /* invalid */
1322 MOD_ACTION_RETURN, /* userlock */
1329 MOD_ACTION_RETURN, /* reject */
1331 MOD_ACTION_RETURN, /* ok */
1332 MOD_ACTION_RETURN, /* handled */
1333 MOD_ACTION_RETURN, /* invalid */
1334 MOD_ACTION_RETURN, /* userlock */
1335 MOD_ACTION_RETURN, /* notfound */
1336 MOD_ACTION_RETURN, /* noop */
1337 MOD_ACTION_RETURN /* updated */
1341 MOD_ACTION_RETURN, /* reject */
1343 MOD_ACTION_RETURN, /* ok */
1344 MOD_ACTION_RETURN, /* handled */
1345 MOD_ACTION_RETURN, /* invalid */
1346 MOD_ACTION_RETURN, /* userlock */
1348 MOD_ACTION_RETURN, /* noop */
1349 MOD_ACTION_RETURN /* updated */
1356 MOD_ACTION_RETURN, /* reject */
1357 MOD_ACTION_RETURN, /* fail */
1359 MOD_ACTION_RETURN, /* handled */
1360 MOD_ACTION_RETURN, /* invalid */
1361 MOD_ACTION_RETURN, /* userlock */
1368 MOD_ACTION_RETURN, /* reject */
1370 MOD_ACTION_RETURN, /* ok */
1371 MOD_ACTION_RETURN, /* handled */
1372 MOD_ACTION_RETURN, /* invalid */
1373 MOD_ACTION_RETURN, /* userlock */
1374 MOD_ACTION_RETURN, /* notfound */
1375 MOD_ACTION_RETURN, /* noop */
1376 MOD_ACTION_RETURN /* updated */
1380 MOD_ACTION_RETURN, /* reject */
1382 MOD_ACTION_RETURN, /* ok */
1383 MOD_ACTION_RETURN, /* handled */
1384 MOD_ACTION_RETURN, /* invalid */
1385 MOD_ACTION_RETURN, /* userlock */
1387 MOD_ACTION_RETURN, /* noop */
1388 MOD_ACTION_RETURN /* updated */
1395 MOD_ACTION_RETURN, /* reject */
1396 MOD_ACTION_RETURN, /* fail */
1398 MOD_ACTION_RETURN, /* handled */
1399 MOD_ACTION_RETURN, /* invalid */
1400 MOD_ACTION_RETURN, /* userlock */
1407 MOD_ACTION_RETURN, /* reject */
1409 MOD_ACTION_RETURN, /* ok */
1410 MOD_ACTION_RETURN, /* handled */
1411 MOD_ACTION_RETURN, /* invalid */
1412 MOD_ACTION_RETURN, /* userlock */
1413 MOD_ACTION_RETURN, /* notfound */
1414 MOD_ACTION_RETURN, /* noop */
1415 MOD_ACTION_RETURN /* updated */
1419 MOD_ACTION_RETURN, /* reject */
1421 MOD_ACTION_RETURN, /* ok */
1422 MOD_ACTION_RETURN, /* handled */
1423 MOD_ACTION_RETURN, /* invalid */
1424 MOD_ACTION_RETURN, /* userlock */
1426 MOD_ACTION_RETURN, /* noop */
1427 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 */
1475 MOD_ACTION_RETURN, /* reject */
1476 MOD_ACTION_RETURN, /* fail */
1478 MOD_ACTION_RETURN, /* handled */
1479 MOD_ACTION_RETURN, /* invalid */
1480 MOD_ACTION_RETURN, /* userlock */
1487 MOD_ACTION_RETURN, /* reject */
1489 MOD_ACTION_RETURN, /* ok */
1490 MOD_ACTION_RETURN, /* handled */
1491 MOD_ACTION_RETURN, /* invalid */
1492 MOD_ACTION_RETURN, /* userlock */
1493 MOD_ACTION_RETURN, /* notfound */
1494 MOD_ACTION_RETURN, /* noop */
1495 MOD_ACTION_RETURN /* updated */
1499 MOD_ACTION_RETURN, /* reject */
1501 MOD_ACTION_RETURN, /* ok */
1502 MOD_ACTION_RETURN, /* handled */
1503 MOD_ACTION_RETURN, /* invalid */
1504 MOD_ACTION_RETURN, /* userlock */
1506 MOD_ACTION_RETURN, /* noop */
1507 MOD_ACTION_RETURN /* updated */
1515 static modcallable *do_compile_modupdate(modcallable *parent, UNUSED rlm_components_t component,
1516 CONF_SECTION *cs, char const *name2)
1520 modcallable *csingle;
1521 value_pair_map_t *map, *head = NULL;
1524 * This looks at cs->name2 to determine which list to update
1526 rcode = radius_attrmap(cs, &head, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, 128);
1527 if (rcode < 0) return NULL; /* message already printed */
1530 cf_log_err_cs(cs, "'update' sections cannot be empty");
1534 for (map = head; map != NULL; map = map->next) {
1535 if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LITERAL)) {
1537 * If LHS is an attribute, and RHS is a literal, we can
1538 * check that the format is correct.
1543 MEM(vp = pairalloc(cs, map->dst->da));
1546 ret = pairparsevalue(vp, map->src->name);
1550 cf_log_err(map->ci, "%s", fr_strerror());
1556 g = rad_malloc(sizeof(*g)); /* never fails */
1557 memset(g, 0, sizeof(*g));
1559 csingle = mod_grouptocallable(g);
1561 csingle->parent = parent;
1562 csingle->next = NULL;
1565 csingle->name = name2;
1569 csingle->type = MOD_UPDATE;
1570 csingle->method = component;
1572 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1573 sizeof(csingle->actions));
1575 g->grouptype = GROUPTYPE_SIMPLE;
1584 static modcallable *do_compile_modswitch(modcallable *parent, UNUSED rlm_components_t component, CONF_SECTION *cs)
1586 modcallable *csingle;
1588 bool had_seen_default = false;
1590 if (!cf_section_name2(cs)) {
1592 "You must specify a variable to switch over for 'switch'.");
1596 if (!cf_item_find_next(cs, NULL)) {
1597 cf_log_err_cs(cs, "'switch' statements cannot be empty.");
1602 * Walk through the children of the switch section,
1603 * ensuring that they're all 'case' statements
1605 for (ci=cf_item_find_next(cs, NULL);
1607 ci=cf_item_find_next(cs, ci)) {
1608 CONF_SECTION *subcs;
1609 char const *name1, *name2;
1611 if (!cf_item_is_section(ci)) {
1612 if (!cf_item_is_pair(ci)) continue;
1614 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1618 subcs = cf_itemtosection(ci); /* can't return NULL */
1619 name1 = cf_section_name1(subcs);
1621 if (strcmp(name1, "case") != 0) {
1622 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1626 name2 = cf_section_name2(subcs);
1627 if (!name2 && !had_seen_default) {
1628 had_seen_default = true;
1632 if (!name2 || (name2[0] == '\0')) {
1633 cf_log_err(ci, "\"case\" sections must have a name");
1638 csingle = do_compile_modgroup(parent, component, cs, GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1639 if (!csingle) return NULL;
1640 csingle->type = MOD_SWITCH;
1644 static modcallable *do_compile_modforeach(modcallable *parent,
1645 UNUSED rlm_components_t component, CONF_SECTION *cs,
1648 modcallable *csingle;
1650 if (!cf_section_name2(cs)) {
1652 "You must specify an attribute to loop over in 'foreach'.");
1656 if (!cf_item_find_next(cs, NULL)) {
1657 cf_log_err_cs(cs, "'foreach' blocks cannot be empty.");
1661 csingle= do_compile_modgroup(parent, component, cs,
1662 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1663 if (!csingle) return NULL;
1664 csingle->name = name2;
1665 csingle->type = MOD_FOREACH;
1669 static modcallable *do_compile_modbreak(modcallable *parent,
1670 rlm_components_t component, CONF_ITEM const *ci)
1672 modcallable *csingle;
1673 CONF_SECTION const *cs = NULL;
1675 for (cs = cf_item_parent(ci);
1677 cs = cf_item_parent(cf_sectiontoitem(cs))) {
1678 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
1684 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
1688 csingle = do_compile_modgroup(parent, component, NULL,
1689 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1690 if (!csingle) return NULL;
1692 csingle->type = MOD_BREAK;
1697 static modcallable *do_compile_modserver(modcallable *parent,
1698 rlm_components_t component, CONF_ITEM *ci,
1703 modcallable *csingle;
1704 CONF_SECTION *subcs;
1707 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
1709 cf_log_err(ci, "Server %s has no %s section",
1710 server, comp2str[component]);
1714 mr = rad_malloc(sizeof(*mr));
1715 memset(mr, 0, sizeof(*mr));
1717 csingle = mod_reftocallable(mr);
1718 csingle->parent = parent;
1719 csingle->next = NULL;
1720 csingle->name = name;
1721 csingle->type = MOD_REFERENCE;
1722 csingle->method = component;
1724 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1725 sizeof(csingle->actions));
1727 mr->ref_name = strdup(server);
1733 static modcallable *do_compile_modxlat(modcallable *parent,
1734 rlm_components_t component, char const *fmt)
1736 modcallable *csingle;
1739 mx = rad_malloc(sizeof(*mx));
1740 memset(mx, 0, sizeof(*mx));
1742 csingle = mod_xlattocallable(mx);
1743 csingle->parent = parent;
1744 csingle->next = NULL;
1745 csingle->name = "expand";
1746 csingle->type = MOD_XLAT;
1747 csingle->method = component;
1749 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1750 sizeof(csingle->actions));
1752 mx->xlat_name = strdup(fmt);
1753 if (fmt[0] != '%') {
1757 strcpy(mx->xlat_name, fmt + 1);
1758 p = strrchr(mx->xlat_name, '`');
1766 * redundant, etc. can refer to modules or groups, but not much else.
1768 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
1772 for (ci=cf_item_find_next(cs, NULL);
1774 ci=cf_item_find_next(cs, ci)) {
1776 * If we're a redundant, etc. group, then the
1777 * intention is to call modules, rather than
1778 * processing logic. These checks aren't
1779 * *strictly* necessary, but they keep the users
1780 * from doing crazy things.
1782 if (cf_item_is_section(ci)) {
1783 CONF_SECTION *subcs = cf_itemtosection(ci);
1784 char const *name1 = cf_section_name1(subcs);
1786 if ((strcmp(name1, "if") == 0) ||
1787 (strcmp(name1, "else") == 0) ||
1788 (strcmp(name1, "elsif") == 0) ||
1789 (strcmp(name1, "update") == 0) ||
1790 (strcmp(name1, "switch") == 0) ||
1791 (strcmp(name1, "case") == 0)) {
1792 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1799 if (cf_item_is_pair(ci)) {
1800 CONF_PAIR *cp = cf_itemtopair(ci);
1801 if (cf_pair_value(cp) != NULL) {
1803 "Entry with no value is invalid");
1814 * Compile one entry of a module call.
1816 static modcallable *do_compile_modsingle(modcallable *parent,
1817 rlm_components_t component, CONF_ITEM *ci,
1819 char const **modname)
1821 char const *modrefname;
1823 modcallable *csingle;
1824 module_instance_t *this;
1825 CONF_SECTION *cs, *subcs, *modules;
1826 char const *realname;
1828 if (cf_item_is_section(ci)) {
1831 cs = cf_itemtosection(ci);
1832 modrefname = cf_section_name1(cs);
1833 name2 = cf_section_name2(cs);
1834 if (!name2) name2 = "";
1837 * group{}, redundant{}, or append{} may appear
1838 * where a single module instance was expected.
1839 * In that case, we hand it off to
1842 if (strcmp(modrefname, "group") == 0) {
1844 return do_compile_modgroup(parent, component, cs,
1848 } else if (strcmp(modrefname, "redundant") == 0) {
1851 if (!all_children_are_modules(cs, modrefname)) {
1855 return do_compile_modgroup(parent, component, cs,
1856 GROUPTYPE_REDUNDANT,
1859 } else if (strcmp(modrefname, "append") == 0) {
1861 return do_compile_modgroup(parent, component, cs,
1865 } else if (strcmp(modrefname, "load-balance") == 0) {
1868 if (!all_children_are_modules(cs, modrefname)) {
1872 csingle= do_compile_modgroup(parent, component, cs,
1875 if (!csingle) return NULL;
1876 csingle->type = MOD_LOAD_BALANCE;
1879 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1882 if (!all_children_are_modules(cs, modrefname)) {
1886 csingle= do_compile_modgroup(parent, component, cs,
1887 GROUPTYPE_REDUNDANT,
1889 if (!csingle) return NULL;
1890 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1894 } else if (strcmp(modrefname, "if") == 0) {
1897 if (!cf_section_name2(cs)) {
1898 cf_log_err(ci, "'if' without condition.");
1903 csingle= do_compile_modgroup(parent, component, cs,
1906 if (!csingle) return NULL;
1907 csingle->type = MOD_IF;
1910 g = mod_callabletogroup(csingle);
1911 g->cond = cf_data_find(g->cs, "if");
1912 rad_assert(g->cond != NULL);
1916 } else if (strcmp(modrefname, "elsif") == 0) {
1920 ((parent->type == MOD_LOAD_BALANCE) ||
1921 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1922 cf_log_err(ci, "'elsif' cannot be used in this section.");
1926 if (!cf_section_name2(cs)) {
1927 cf_log_err(ci, "'elsif' without condition.");
1932 csingle= do_compile_modgroup(parent, component, cs,
1935 if (!csingle) return NULL;
1936 csingle->type = MOD_ELSIF;
1939 g = mod_callabletogroup(csingle);
1940 g->cond = cf_data_find(g->cs, "if");
1941 rad_assert(g->cond != NULL);
1945 } else if (strcmp(modrefname, "else") == 0) {
1947 ((parent->type == MOD_LOAD_BALANCE) ||
1948 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1949 cf_log_err(ci, "'else' cannot be used in this section section.");
1953 if (cf_section_name2(cs)) {
1954 cf_log_err(ci, "Cannot have conditions on 'else'.");
1959 csingle= do_compile_modgroup(parent, component, cs,
1962 if (!csingle) return NULL;
1963 csingle->type = MOD_ELSE;
1966 } else if (strcmp(modrefname, "update") == 0) {
1969 csingle = do_compile_modupdate(parent, component, cs,
1971 if (!csingle) return NULL;
1975 } else if (strcmp(modrefname, "switch") == 0) {
1978 csingle = do_compile_modswitch(parent, component, cs);
1979 if (!csingle) return NULL;
1983 } else if (strcmp(modrefname, "case") == 0) {
1989 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1993 csingle= do_compile_modgroup(parent, component, cs,
1996 if (!csingle) return NULL;
1997 csingle->type = MOD_CASE;
1998 csingle->name = cf_section_name2(cs); /* may be NULL */
2001 * Set all of it's codes to return, so that
2002 * when we pick a 'case' statement, we don't
2003 * fall through to processing the next one.
2005 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2006 csingle->actions[i] = MOD_ACTION_RETURN;
2011 } else if (strcmp(modrefname, "foreach") == 0) {
2014 csingle = do_compile_modforeach(parent, component, cs,
2016 if (!csingle) return NULL;
2020 } /* else it's something like sql { fail = 1 ...} */
2022 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2026 * Else it's a module reference, with updated return
2031 CONF_PAIR *cp = cf_itemtopair(ci);
2032 modrefname = cf_pair_attr(cp);
2035 * Actions (ok = 1), etc. are orthoganal to just
2036 * about everything else.
2038 if (cf_pair_value(cp) != NULL) {
2039 cf_log_err(ci, "Entry is not a reference to a module");
2043 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2044 (modrefname[0] == '`')) {
2045 return do_compile_modxlat(parent, component,
2050 * See if the module is a virtual one. If so,
2051 * return that, rather than doing anything here.
2054 cs = cf_section_find("instantiate");
2055 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
2058 (cs = cf_section_find("policy")) != NULL) {
2061 snprintf(buffer, sizeof(buffer), "%s.%s",
2062 modrefname, comp2str[component]);
2065 * Prefer name.section, then name.
2067 subcs = cf_section_sub_find_name2(cs, NULL,
2070 subcs = cf_section_sub_find_name2(cs, NULL,
2076 * Allow policies to over-ride module names.
2077 * i.e. the "sql" policy can do some extra things,
2078 * and then call the "sql" module.
2080 for (loop = cf_item_parent(ci);
2082 loop = cf_item_parent(cf_sectiontoitem(loop))) {
2083 if (loop == subcs) {
2090 * redundant foo {} is a single.
2092 if (cf_section_name2(subcs)) {
2093 return do_compile_modsingle(parent,
2095 cf_sectiontoitem(subcs),
2100 * foo {} is a group.
2102 return do_compile_modgroup(parent,
2112 if (strcmp(modrefname, "break") == 0) {
2113 return do_compile_modbreak(parent, component, ci);
2118 * Not a virtual module. It must be a real module.
2120 modules = cf_section_find("modules");
2122 realname = modrefname;
2126 * Try to load the optional module.
2128 if (realname[0] == '-') realname++;
2131 * As of v3, only known modules are in the
2132 * "modules" section.
2134 if (cf_section_sub_find_name2(modules, NULL, realname)) {
2135 this = find_module_instance(modules, realname, 1);
2136 if (!this && (realname != modrefname)) {
2142 * We were asked to MAYBE load it and it
2143 * doesn't exist. Return a soft error.
2145 if (realname != modrefname) {
2146 *modname = modrefname;
2157 * Maybe it's module.method
2159 p = strrchr(modrefname, '.');
2160 if (p) for (i = RLM_COMPONENT_AUTH;
2161 i < RLM_COMPONENT_COUNT;
2163 if (strcmp(p + 1, comp2str[i]) == 0) {
2166 strlcpy(buffer, modrefname, sizeof(buffer));
2167 buffer[p - modrefname] = '\0';
2170 this = find_module_instance(modules, buffer, 1);
2172 !this->entry->module->methods[i]) {
2174 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
2183 * Call a server. This should really be deleted...
2185 if (strncmp(modrefname, "server[", 7) == 0) {
2188 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2189 p = strrchr(buffer, ']');
2190 if (!p || p[1] != '\0' || (p == buffer)) {
2191 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2196 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2198 cf_log_err(ci, "No such server \"%s\".", buffer);
2202 return do_compile_modserver(parent, component, ci,
2203 modrefname, cs, buffer);
2207 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
2212 * We know it's all OK, allocate the structures, and fill
2215 single = rad_malloc(sizeof(*single));
2216 memset(single, 0, sizeof(*single));
2217 csingle = mod_singletocallable(single);
2218 csingle->parent = parent;
2219 csingle->next = NULL;
2220 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2221 memcpy(csingle->actions, defaultactions[component][grouptype],
2222 sizeof csingle->actions);
2223 } else { /* inside Auth-Type has different rules */
2224 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2225 sizeof csingle->actions);
2227 rad_assert(modrefname != NULL);
2228 csingle->name = realname;
2229 csingle->type = MOD_SINGLE;
2230 csingle->method = component;
2233 * Singles can override the actions, virtual modules cannot.
2235 * FIXME: We may want to re-visit how to do this...
2236 * maybe a csingle as a ref?
2238 if (cf_item_is_section(ci)) {
2241 cs = cf_itemtosection(ci);
2242 for (csi=cf_item_find_next(cs, NULL);
2244 csi=cf_item_find_next(cs, csi)) {
2246 if (cf_item_is_section(csi)) {
2247 cf_log_err(csi, "Subsection of module instance call not allowed");
2248 modcallable_free(&csingle);
2252 if (!cf_item_is_pair(csi)) continue;
2254 if (!compile_action(csingle, cf_itemtopair(csi))) {
2255 modcallable_free(&csingle);
2262 * Bail out if the module in question does not supply the
2265 if (!this->entry->module->methods[component]) {
2266 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2267 comp2str[component]);
2268 modcallable_free(&csingle);
2272 single->modinst = this;
2273 *modname = this->entry->module->name;
2277 modcallable *compile_modsingle(modcallable *parent,
2278 rlm_components_t component, CONF_ITEM *ci,
2279 char const **modname)
2281 modcallable *ret = do_compile_modsingle(parent, component, ci,
2284 dump_tree(component, ret);
2290 * Internal compile group code.
2292 static modcallable *do_compile_modgroup(modcallable *parent,
2293 rlm_components_t component, CONF_SECTION *cs,
2294 int grouptype, int parentgrouptype)
2301 g = rad_malloc(sizeof(*g));
2302 memset(g, 0, sizeof(*g));
2303 g->grouptype = grouptype;
2307 c = mod_grouptocallable(g);
2309 c->type = MOD_GROUP;
2311 memset(c->actions, 0, sizeof(c->actions));
2313 if (!cs) { /* only for "break" */
2319 * Remember the name for printing, etc.
2321 * FIXME: We may also want to put the names into a
2322 * rbtree, so that groups can reference each other...
2324 c->name = cf_section_name2(cs);
2326 c->name = cf_section_name1(cs);
2327 if (strcmp(c->name, "group") == 0) {
2330 c->type = MOD_POLICY;
2335 * Loop over the children of this group.
2337 for (ci=cf_item_find_next(cs, NULL);
2339 ci=cf_item_find_next(cs, ci)) {
2342 * Sections are references to other groups, or
2343 * to modules with updated return codes.
2345 if (cf_item_is_section(ci)) {
2346 char const *junk = NULL;
2347 modcallable *single;
2348 CONF_SECTION *subcs = cf_itemtosection(ci);
2350 single = do_compile_modsingle(c, component, ci,
2353 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2354 cf_section_name1(subcs));
2355 modcallable_free(&c);
2358 add_child(g, single);
2360 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2364 char const *attr, *value;
2365 CONF_PAIR *cp = cf_itemtopair(ci);
2367 attr = cf_pair_attr(cp);
2368 value = cf_pair_value(cp);
2371 * A CONF_PAIR is either a module
2372 * instance with no actions
2376 modcallable *single;
2377 char const *junk = NULL;
2379 single = do_compile_modsingle(c,
2385 if (cf_item_is_pair(ci) &&
2386 cf_pair_attr(cf_itemtopair(ci))[0] == '-') {
2391 "Failed to parse \"%s\" entry.",
2393 modcallable_free(&c);
2396 add_child(g, single);
2399 * Or a module instance with action.
2401 } else if (!compile_action(c, cp)) {
2402 modcallable_free(&c);
2404 } /* else it worked */
2410 * Set the default actions, if they haven't already been
2413 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2414 if (!c->actions[i]) {
2415 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2416 c->actions[i] = defaultactions[component][parentgrouptype][i];
2417 } else { /* inside Auth-Type has different rules */
2418 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2424 * FIXME: If there are no children, return NULL?
2426 return mod_grouptocallable(g);
2429 modcallable *compile_modgroup(modcallable *parent,
2430 rlm_components_t component, CONF_SECTION *cs)
2432 modcallable *ret = do_compile_modgroup(parent, component, cs,
2435 dump_tree(component, ret);
2439 void add_to_modcallable(modcallable **parent, modcallable *this,
2440 rlm_components_t component, char const *name)
2444 rad_assert(this != NULL);
2446 if (*parent == NULL) {
2449 g = rad_malloc(sizeof *g);
2450 memset(g, 0, sizeof(*g));
2451 g->grouptype = GROUPTYPE_SIMPLE;
2452 c = mod_grouptocallable(g);
2455 defaultactions[component][GROUPTYPE_SIMPLE],
2456 sizeof(c->actions));
2457 rad_assert(name != NULL);
2459 c->type = MOD_GROUP;
2460 c->method = component;
2463 *parent = mod_grouptocallable(g);
2465 g = mod_callabletogroup(*parent);
2471 void modcallable_free(modcallable **pc)
2473 modcallable *c, *loop, *next;
2475 if (!pc || !*pc) return;
2479 if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
2480 modgroup *g = mod_callabletogroup(c);
2482 if (g->children) for (loop = g->children;
2486 modcallable_free(&loop);
2488 talloc_free(g->map);
2496 static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
2498 value_pair_map_t *map;
2501 * Maps have a paircompare fixup applied to them.
2502 * Others get ignored.
2504 if (c->pass2_fixup == PASS2_FIXUP_NONE) {
2505 if (c->type == COND_TYPE_MAP) {
2512 map = c->data.map; /* shorter */
2517 * Where "foo" is dynamically defined.
2519 if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
2520 if (!dict_valbyname(map->dst->da->attr,
2521 map->dst->da->vendor,
2523 cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
2530 * These guys can't have a paircompare fixup applied.
2532 c->pass2_fixup = PASS2_FIXUP_NONE;
2536 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
2537 value_pair_map_t *old;
2538 value_pair_tmpl_t vpt;
2543 * It's still not an attribute. Ignore it.
2545 if (radius_parse_attr(&vpt, map->dst->name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
2546 cf_log_err(old->ci, "Failed parsing condition: %s", fr_strerror());
2547 c->pass2_fixup = PASS2_FIXUP_NONE;
2552 * Re-parse the LHS as an attribute.
2554 map = radius_str2map(c, old->dst->name, T_BARE_WORD, old->op,
2555 old->src->name, T_BARE_WORD,
2556 REQUEST_CURRENT, PAIR_LIST_REQUEST,
2557 REQUEST_CURRENT, PAIR_LIST_REQUEST);
2559 cf_log_err(old->ci, "Failed parsing condition");
2565 c->pass2_fixup = PASS2_FIXUP_NONE;
2570 * Just in case someone adds a new fixup later.
2572 rad_assert(c->pass2_fixup == PASS2_FIXUP_NONE);
2575 * Only attributes can have a paircompare registered, and
2576 * they can only be with the current REQUEST, and only
2577 * with the request pairs.
2579 if ((map->dst->type != VPT_TYPE_ATTR) ||
2580 (map->dst->request != REQUEST_CURRENT) ||
2581 (map->dst->list != PAIR_LIST_REQUEST)) {
2585 if (!radius_find_compare(map->dst->da)) return true;
2587 if (map->src->type == VPT_TYPE_ATTR) {
2588 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
2593 if (map->src->type == VPT_TYPE_REGEX) {
2594 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
2600 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
2605 if (map->op != T_OP_CMP_EQ) {
2606 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
2612 * Mark it as requiring a paircompare() call, instead of
2615 c->pass2_fixup = PASS2_PAIRCOMPARE;
2622 * Do a second-stage pass on compiling the modules.
2624 bool modcall_pass2(modcallable *mc)
2629 for (this = mc; this != NULL; this = this->next) {
2630 switch (this->type) {
2637 case MOD_UPDATE: /* @todo: pre-parse xlat's */
2638 case MOD_XLAT: /* @todo: pre-parse xlat's */
2642 break; /* do nothing */
2647 g = mod_callabletogroup(this);
2648 if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
2655 case MOD_LOAD_BALANCE:
2656 case MOD_REDUNDANT_LOAD_BALANCE:
2665 g = mod_callabletogroup(this);
2666 if (!modcall_pass2(g->children)) return false;