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 char const *debug_name;
52 enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
54 MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
55 MOD_FOREACH, MOD_BREAK, MOD_RETURN,
57 MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
58 rlm_components_t method;
59 int actions[RLM_MODULE_NUMCODES];
62 #define MOD_LOG_OPEN_BRACE RDEBUG2("%s {", c->debug_name)
64 #define MOD_LOG_CLOSE_BRACE RDEBUG2("} # %s = %s", c->debug_name, 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;
100 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
101 * so we often want to go back and forth between them. */
102 static modsingle *mod_callabletosingle(modcallable *p)
104 rad_assert(p->type==MOD_SINGLE);
105 return (modsingle *)p;
107 static modgroup *mod_callabletogroup(modcallable *p)
109 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
111 return (modgroup *)p;
113 static modcallable *mod_singletocallable(modsingle *p)
115 return (modcallable *)p;
117 static modcallable *mod_grouptocallable(modgroup *p)
119 return (modcallable *)p;
122 static modref *mod_callabletoref(modcallable *p)
124 rad_assert(p->type==MOD_REFERENCE);
127 static modcallable *mod_reftocallable(modref *p)
129 return (modcallable *)p;
132 static modxlat *mod_callabletoxlat(modcallable *p)
134 rad_assert(p->type==MOD_XLAT);
137 static modcallable *mod_xlattocallable(modxlat *p)
139 return (modcallable *)p;
142 /* modgroups are grown by adding a modcallable to the end */
143 static void add_child(modgroup *g, modcallable *c)
147 (void) talloc_steal(g, c);
150 g->children = g->tail = c;
152 rad_assert(g->tail->next == NULL);
157 c->parent = mod_grouptocallable(g);
160 /* Here's where we recognize all of our keywords: first the rcodes, then the
162 const FR_NAME_NUMBER mod_rcode_table[] = {
163 { "reject", RLM_MODULE_REJECT },
164 { "fail", RLM_MODULE_FAIL },
165 { "ok", RLM_MODULE_OK },
166 { "handled", RLM_MODULE_HANDLED },
167 { "invalid", RLM_MODULE_INVALID },
168 { "userlock", RLM_MODULE_USERLOCK },
169 { "notfound", RLM_MODULE_NOTFOUND },
170 { "noop", RLM_MODULE_NOOP },
171 { "updated", RLM_MODULE_UPDATED },
176 static char const *group_name[];
179 * Compile action && rcode for later use.
181 static int compile_action(modcallable *c, CONF_PAIR *cp)
184 char const *attr, *value;
186 attr = cf_pair_attr(cp);
187 value = cf_pair_value(cp);
188 if (!value) return 0;
190 if (c->type != MOD_SINGLE) {
191 ERROR("%s[%d] Invalid return code assigment inside of a %s section",
192 cf_pair_filename(cp), cf_pair_lineno(cp), group_name[c->type]);
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 CC_HINT(nonnull) call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
287 int indent = request->log.indent;
290 * If the request should stop, refuse to do anything.
292 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
293 if (blocked) return RLM_MODULE_NOOP;
295 RDEBUG3("modsingle[%s]: calling %s (%s) for request %d",
296 comp2str[component], sp->modinst->name,
297 sp->modinst->entry->name, request->number);
298 request->log.indent = 0;
300 if (sp->modinst->force) {
301 request->rcode = sp->modinst->code;
306 * For logging unresponsive children.
308 request->module = sp->modinst->name;
310 safe_lock(sp->modinst);
311 request->rcode = sp->modinst->entry->module->methods[component](sp->modinst->insthandle, request);
312 safe_unlock(sp->modinst);
314 request->module = "";
317 * Wasn't blocked, and now is. Complain!
319 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
321 RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
325 request->log.indent = indent;
326 RDEBUG3("modsingle[%s]: returned from %s (%s) for request %d",
327 comp2str[component], sp->modinst->name,
328 sp->modinst->entry->name, request->number);
330 return request->rcode;
333 static int default_component_results[RLM_COMPONENT_COUNT] = {
334 RLM_MODULE_REJECT, /* AUTH */
335 RLM_MODULE_NOTFOUND, /* AUTZ */
336 RLM_MODULE_NOOP, /* PREACCT */
337 RLM_MODULE_NOOP, /* ACCT */
338 RLM_MODULE_FAIL, /* SESS */
339 RLM_MODULE_NOOP, /* PRE_PROXY */
340 RLM_MODULE_NOOP, /* POST_PROXY */
341 RLM_MODULE_NOOP /* POST_AUTH */
344 RLM_MODULE_NOOP, /* RECV_COA_TYPE */
345 RLM_MODULE_NOOP /* SEND_COA_TYPE */
350 static char const *group_name[] = {
354 "load-balance group",
355 "redundant-load-balance group",
372 static char const modcall_spaces[] = " ";
374 #define MODCALL_STACK_MAX (32)
377 * Don't call the modules recursively. Instead, do them
378 * iteratively, and manage the call stack ourselves.
380 typedef struct modcall_stack_entry_t {
383 int unwind; /* unwind to this one if it exists */
385 } modcall_stack_entry_t;
388 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
389 modcall_stack_entry_t *entry);
392 * Call a child of a block.
394 static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
395 modcall_stack_entry_t *entry, modcallable *c,
398 modcall_stack_entry_t *next;
400 if (depth >= MODCALL_STACK_MAX) {
401 ERROR("Internal sanity check failed: module stack is too deep");
406 * Initialize the childs stack frame.
410 next->result = entry->result;
414 if (!modcall_recurse(request, component,
416 *result = RLM_MODULE_FAIL;
421 * Unwind back up the stack
423 if (next->unwind != 0) {
424 entry->unwind = next->unwind;
427 *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;
453 * Nothing more to do. Return the code and priority
454 * which was set by the caller.
459 * We've been asked to stop. Do so.
461 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
463 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
464 entry->result = RLM_MODULE_FAIL;
465 entry->priority = 9999;
471 * Handle "if" conditions.
473 if (c->type == MOD_IF) {
478 g = mod_callabletogroup(c);
479 rad_assert(g->cond != NULL);
481 RDEBUG2("%s %s{", 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",
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("... skipping %s for request %d: Preceding \"if\" was taken",
522 group_name[c->type], request->number);
529 * Check the "if" condition.
535 * "else" for a preceding "if".
537 if (c->type == MOD_ELSE) {
538 if (!was_if) { /* error */
540 RDEBUG2("... skipping %s for request %d: No preceding \"if\"",
541 group_name[c->type], request->number);
546 RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
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", 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;
595 for (map = g->map; map != NULL; map = map->next) {
596 rcode = map_to_request(request, map, map_to_vp, NULL);
598 result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
601 goto calculate_result;
605 result = RLM_MODULE_NOOP;
607 goto calculate_result;
611 * Loop over a set of attributes.
613 if (c->type == MOD_FOREACH) {
614 int i, foreach_depth = -1;
615 VALUE_PAIR *vps, *vp;
616 modcall_stack_entry_t *next = NULL;
618 modgroup *g = mod_callabletogroup(c);
620 if (depth >= MODCALL_STACK_MAX) {
621 ERROR("Internal sanity check failed: module stack is too deep");
626 * Figure out how deep we are in nesting by looking at request_data
629 for (i = 0; i < 8; i++) {
630 if (!request_data_reference(request,
637 if (foreach_depth < 0) {
638 REDEBUG("foreach Nesting too deep!");
639 result = RLM_MODULE_FAIL;
640 goto calculate_result;
644 * Copy the VPs from the original request, this ensures deterministic
645 * behaviour if someone decides to add or remove VPs in the set were
648 if (tmpl_copy_vps(request, &vps, request, g->vpt) < 0) { /* nothing to loop over */
650 result = RLM_MODULE_NOOP;
652 goto calculate_result;
655 rad_assert(vps != NULL);
656 fr_cursor_init(©, &vps);
658 RDEBUG2("foreach %s ", c->name);
661 * This is the actual body of the foreach loop
663 for (vp = fr_cursor_first(©);
665 vp = fr_cursor_next(©)) {
667 if (fr_debug_flag >= 2) {
670 vp_prints_value(buffer, sizeof(buffer), vp, '"');
671 RDEBUG2("# Foreach-Variable-%d = %s", foreach_depth, buffer);
676 * Add the vp to the request, so that
677 * xlat.c, xlat_foreach() can find it.
679 request_data_add(request, radius_get_vp, foreach_depth, &vp, false);
682 * Initialize the childs stack frame.
685 next->c = g->children;
686 next->result = entry->result;
690 if (!modcall_recurse(request, component, depth + 1, next)) {
695 * We've unwound to the enclosing
696 * "foreach". Stop the unwinding.
698 if (next->unwind == MOD_FOREACH) {
703 * Unwind all the way.
705 if (next->unwind == MOD_RETURN) {
706 entry->unwind = MOD_RETURN;
709 } /* loop over VPs */
712 * Free the copied vps and the request data
713 * If we don't remove the request data, something could call
714 * the xlat outside of a foreach loop and trigger a segv.
717 request_data_get(request, radius_get_vp, foreach_depth);
719 rad_assert(next != NULL);
720 result = next->result;
721 priority = next->priority;
723 goto calculate_result;
727 * Break out of a "foreach" loop, or return from a nested
730 if ((c->type == MOD_BREAK) || (c->type == MOD_RETURN)) {
734 RDEBUG2("%s", group_name[c->type]);
736 for (i = 8; i >= 0; i--) {
737 copy_p = request_data_get(request, radius_get_vp, i);
739 if (c->type == MOD_BREAK) {
740 RDEBUG2("# break Foreach-Variable-%d", i);
747 * Leave result / priority on the stack, and stop processing the section.
749 entry->unwind = c->type;
753 #endif /* WITH_UNLANG */
756 * Child is a group that has children of it's own.
758 if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
760 || (c->type == MOD_CASE)
768 g = mod_callabletogroup(c);
771 * This should really have been caught in the
772 * compiler, and the node never generated. But
773 * doing that requires changing it's API so that
774 * it returns a flag instead of the compiled
778 RDEBUG2("%s { ... } # empty sub-section is ignored", c->name);
783 modcall_child(request, component,
784 depth + 1, entry, g->children,
787 goto calculate_result;
791 if (c->type == MOD_SWITCH) {
792 modcallable *this, *found, *null_case;
796 value_pair_map_t map;
797 value_pair_tmpl_t vpt;
801 g = mod_callabletogroup(c);
803 memset(&cond, 0, sizeof(cond));
804 memset(&map, 0, sizeof(map));
806 cond.type = COND_TYPE_MAP;
807 cond.data.map = ↦
809 map.op = T_OP_CMP_EQ;
810 map.ci = cf_sectiontoitem(g->cs);
812 rad_assert(g->vpt != NULL);
814 null_case = found = NULL;
817 * The attribute doesn't exist. We can skip
818 * directly to the default 'case' statement.
820 if ((g->vpt->type == TMPL_TYPE_ATTR) && (tmpl_find_vp(NULL, request, g->vpt) < 0)) {
822 for (this = g->children; this; this = this->next) {
823 rad_assert(this->type == MOD_CASE);
825 h = mod_callabletogroup(this);
826 if (h->vpt) continue;
836 * Expand the template if necessary, so that it
837 * is evaluated once instead of for each 'case'
840 if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
841 (g->vpt->type == TMPL_TYPE_XLAT) ||
842 (g->vpt->type == TMPL_TYPE_EXEC)) {
843 if (radius_expand_tmpl(&data, request, g->vpt) < 0) goto find_null_case;
844 tmpl_init(&vpt, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
850 * Find either the exact matching name, or the
851 * "case {...}" statement.
853 for (this = g->children; this; this = this->next) {
854 rad_assert(this->type == MOD_CASE);
856 h = mod_callabletogroup(this);
859 * Remember the default case
862 if (!null_case) null_case = this;
867 * If we're switching over an attribute
868 * AND we haven't pre-parsed the data for
869 * the case statement, then cast the data
870 * to the type of the attribute.
872 if ((g->vpt->type == TMPL_TYPE_ATTR) &&
873 (h->vpt->type != TMPL_TYPE_DATA)) {
876 cond.cast = g->vpt->tmpl_da;
879 * Remove unnecessary casting.
881 if ((h->vpt->type == TMPL_TYPE_ATTR) &&
882 (g->vpt->tmpl_da->type == h->vpt->tmpl_da->type)) {
887 * Use the pre-expanded string.
889 } else if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
890 (g->vpt->type == TMPL_TYPE_XLAT) ||
891 (g->vpt->type == TMPL_TYPE_EXEC)) {
897 * Else evaluate the 'switch' statement.
905 if (radius_evaluate_map(request, RLM_MODULE_UNKNOWN, 0,
912 if (!found) found = null_case;
915 talloc_free(data.ptr);
916 modcall_child(request, component, depth + 1, entry, found, &result);
918 goto calculate_result;
922 if ((c->type == MOD_LOAD_BALANCE) ||
923 (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
925 modcallable *this, *found;
930 g = mod_callabletogroup(c);
932 rad_assert(g->children != NULL);
935 * Choose a child at random.
937 for (this = g->children; this; this = this->next) {
940 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
947 if (c->type == MOD_LOAD_BALANCE) {
948 modcall_child(request, component,
949 depth + 1, entry, found,
956 modcall_child(request, component,
957 depth + 1, entry, this,
959 if (this->actions[result] == MOD_ACTION_RETURN) {
965 if (!this) this = g->children;
966 } while (this != found);
969 goto calculate_result;
970 } /* MOD_LOAD_BALANCE */
973 * Reference another virtual server.
975 * This should really be deleted, and replaced with a
976 * more abstracted / functional version.
978 if (c->type == MOD_REFERENCE) {
979 modref *mr = mod_callabletoref(c);
980 char const *server = request->server;
982 if (server == mr->ref_name) {
983 RWDEBUG("Suppressing recursive call to server %s", server);
987 request->server = mr->ref_name;
988 RDEBUG("server %s { # nested call", mr->ref_name);
989 result = indexed_modcall(component, 0, request);
990 RDEBUG("} # server %s with nested call", mr->ref_name);
991 request->server = server;
992 goto calculate_result;
993 } /* MOD_REFERENCE */
996 * xlat a string without doing anything else
998 * This should really be deleted, and replaced with a
999 * more abstracted / functional version.
1001 if (c->type == MOD_XLAT) {
1002 modxlat *mx = mod_callabletoxlat(c);
1006 radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
1008 RDEBUG("`%s`", mx->xlat_name);
1009 radius_exec_program(NULL, 0, NULL, request, mx->xlat_name, request->packet->vps,
1010 false, true, EXEC_TIMEOUT);
1017 * Add new module types here.
1022 RDEBUG("(%s, %d) ? (%s, %d)",
1023 fr_int2str(mod_rcode_table, result, "<invalid>"),
1025 fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
1030 rad_assert(result != RLM_MODULE_UNKNOWN);
1033 * The child's action says return. Do so.
1035 if ((c->actions[result] == MOD_ACTION_RETURN) &&
1037 entry->result = result;
1042 * If "reject", break out of the loop and return
1045 if (c->actions[result] == MOD_ACTION_REJECT) {
1046 entry->result = RLM_MODULE_REJECT;
1051 * The array holds a default priority for this return
1052 * code. Grab it in preference to any unset priority.
1055 priority = c->actions[result];
1059 * We're higher than any previous priority, remember this
1060 * return code and priority.
1062 if (priority > entry->priority) {
1063 entry->result = result;
1064 entry->priority = priority;
1069 * If we're processing a "case" statement, we return once
1070 * it's done, rather than going to the next "case" statement.
1072 if (c->type == MOD_CASE) goto finish;
1076 * If we've been told to stop processing
1079 if (entry->unwind == MOD_BREAK) {
1080 RDEBUG2("# unwind to enclosing foreach");
1085 if (entry->unwind == MOD_RETURN) {
1090 entry->c = entry->c->next;
1092 if (entry->c) goto redo;
1103 /** Call a module, iteratively, with a local stack, rather than recursively
1105 * What did Paul Graham say about Lisp...?
1107 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1109 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1112 memset(stack, 0, sizeof(stack));
1115 * Set up the initial stack frame.
1118 stack[0].result = default_component_results[component];
1119 stack[0].priority = 0;
1120 stack[0].unwind = 0;
1123 * Call the main handler.
1125 if (!modcall_recurse(request, component, 0, &stack[0])) {
1126 return RLM_MODULE_FAIL;
1130 * Return the result.
1132 return stack[0].result;
1137 static char const *action2str(int action)
1139 static char buf[32];
1140 if(action==MOD_ACTION_RETURN)
1142 if(action==MOD_ACTION_REJECT)
1144 snprintf(buf, sizeof buf, "%d", action);
1148 /* If you suspect a bug in the parser, you'll want to use these dump
1149 * functions. dump_tree should reproduce a whole tree exactly as it was found
1150 * in radiusd.conf, but in long form (all actions explicitly defined) */
1151 static void dump_mc(modcallable *c, int indent)
1155 if(c->type==MOD_SINGLE) {
1156 modsingle *single = mod_callabletosingle(c);
1157 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1158 single->modinst->name);
1159 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1160 modgroup *g = mod_callabletogroup(c);
1162 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1163 group_name[c->type]);
1164 for(p = g->children;p;p = p->next)
1165 dump_mc(p, indent+1);
1166 } /* else ignore it for now */
1168 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1169 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1170 fr_int2str(mod_rcode_table, i, "<invalid>"),
1171 action2str(c->actions[i]));
1174 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1177 static void dump_tree(rlm_components_t comp, modcallable *c)
1179 DEBUG("[%s]", comp2str[comp]);
1183 #define dump_tree(a, b)
1186 /* These are the default actions. For each component, the group{} block
1187 * behaves like the code from the old module_*() function. redundant{} and
1188 * append{} are based on my guesses of what they will be used for. --Pac. */
1190 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1196 MOD_ACTION_RETURN, /* reject */
1198 MOD_ACTION_RETURN, /* ok */
1199 MOD_ACTION_RETURN, /* handled */
1201 MOD_ACTION_RETURN, /* userlock */
1202 MOD_ACTION_RETURN, /* notfound */
1208 MOD_ACTION_RETURN, /* reject */
1210 MOD_ACTION_RETURN, /* ok */
1211 MOD_ACTION_RETURN, /* handled */
1212 MOD_ACTION_RETURN, /* invalid */
1213 MOD_ACTION_RETURN, /* userlock */
1214 MOD_ACTION_RETURN, /* notfound */
1215 MOD_ACTION_RETURN, /* noop */
1216 MOD_ACTION_RETURN /* updated */
1220 MOD_ACTION_RETURN, /* reject */
1222 MOD_ACTION_RETURN, /* ok */
1223 MOD_ACTION_RETURN, /* handled */
1224 MOD_ACTION_RETURN, /* invalid */
1225 MOD_ACTION_RETURN, /* userlock */
1227 MOD_ACTION_RETURN, /* noop */
1228 MOD_ACTION_RETURN /* updated */
1235 MOD_ACTION_RETURN, /* reject */
1236 MOD_ACTION_RETURN, /* fail */
1238 MOD_ACTION_RETURN, /* handled */
1239 MOD_ACTION_RETURN, /* invalid */
1240 MOD_ACTION_RETURN, /* userlock */
1247 MOD_ACTION_RETURN, /* reject */
1249 MOD_ACTION_RETURN, /* ok */
1250 MOD_ACTION_RETURN, /* handled */
1251 MOD_ACTION_RETURN, /* invalid */
1252 MOD_ACTION_RETURN, /* userlock */
1253 MOD_ACTION_RETURN, /* notfound */
1254 MOD_ACTION_RETURN, /* noop */
1255 MOD_ACTION_RETURN /* updated */
1259 MOD_ACTION_RETURN, /* reject */
1261 MOD_ACTION_RETURN, /* ok */
1262 MOD_ACTION_RETURN, /* handled */
1263 MOD_ACTION_RETURN, /* invalid */
1264 MOD_ACTION_RETURN, /* userlock */
1266 MOD_ACTION_RETURN, /* noop */
1267 MOD_ACTION_RETURN /* updated */
1274 MOD_ACTION_RETURN, /* reject */
1275 MOD_ACTION_RETURN, /* fail */
1277 MOD_ACTION_RETURN, /* handled */
1278 MOD_ACTION_RETURN, /* invalid */
1279 MOD_ACTION_RETURN, /* userlock */
1280 MOD_ACTION_RETURN, /* notfound */
1286 MOD_ACTION_RETURN, /* reject */
1288 MOD_ACTION_RETURN, /* ok */
1289 MOD_ACTION_RETURN, /* handled */
1290 MOD_ACTION_RETURN, /* invalid */
1291 MOD_ACTION_RETURN, /* userlock */
1292 MOD_ACTION_RETURN, /* notfound */
1293 MOD_ACTION_RETURN, /* noop */
1294 MOD_ACTION_RETURN /* updated */
1298 MOD_ACTION_RETURN, /* reject */
1300 MOD_ACTION_RETURN, /* ok */
1301 MOD_ACTION_RETURN, /* handled */
1302 MOD_ACTION_RETURN, /* invalid */
1303 MOD_ACTION_RETURN, /* userlock */
1305 MOD_ACTION_RETURN, /* noop */
1306 MOD_ACTION_RETURN /* updated */
1313 MOD_ACTION_RETURN, /* reject */
1314 MOD_ACTION_RETURN, /* fail */
1316 MOD_ACTION_RETURN, /* handled */
1317 MOD_ACTION_RETURN, /* invalid */
1318 MOD_ACTION_RETURN, /* userlock */
1319 MOD_ACTION_RETURN, /* notfound */
1327 MOD_ACTION_RETURN, /* ok */
1328 MOD_ACTION_RETURN, /* handled */
1337 MOD_ACTION_RETURN, /* reject */
1339 MOD_ACTION_RETURN, /* ok */
1340 MOD_ACTION_RETURN, /* handled */
1341 MOD_ACTION_RETURN, /* invalid */
1342 MOD_ACTION_RETURN, /* userlock */
1344 MOD_ACTION_RETURN, /* noop */
1345 MOD_ACTION_RETURN /* updated */
1352 MOD_ACTION_RETURN, /* reject */
1354 MOD_ACTION_RETURN, /* ok */
1355 MOD_ACTION_RETURN, /* handled */
1356 MOD_ACTION_RETURN, /* invalid */
1357 MOD_ACTION_RETURN, /* userlock */
1358 MOD_ACTION_RETURN, /* notfound */
1359 MOD_ACTION_RETURN, /* noop */
1360 MOD_ACTION_RETURN /* updated */
1364 MOD_ACTION_RETURN, /* reject */
1366 MOD_ACTION_RETURN, /* ok */
1367 MOD_ACTION_RETURN, /* handled */
1368 MOD_ACTION_RETURN, /* invalid */
1369 MOD_ACTION_RETURN, /* userlock */
1370 MOD_ACTION_RETURN, /* notfound */
1371 MOD_ACTION_RETURN, /* noop */
1372 MOD_ACTION_RETURN /* updated */
1376 MOD_ACTION_RETURN, /* reject */
1378 MOD_ACTION_RETURN, /* ok */
1379 MOD_ACTION_RETURN, /* handled */
1380 MOD_ACTION_RETURN, /* invalid */
1381 MOD_ACTION_RETURN, /* userlock */
1382 MOD_ACTION_RETURN, /* notfound */
1383 MOD_ACTION_RETURN, /* noop */
1384 MOD_ACTION_RETURN /* updated */
1391 MOD_ACTION_RETURN, /* reject */
1392 MOD_ACTION_RETURN, /* fail */
1394 MOD_ACTION_RETURN, /* handled */
1395 MOD_ACTION_RETURN, /* invalid */
1396 MOD_ACTION_RETURN, /* userlock */
1403 MOD_ACTION_RETURN, /* reject */
1405 MOD_ACTION_RETURN, /* ok */
1406 MOD_ACTION_RETURN, /* handled */
1407 MOD_ACTION_RETURN, /* invalid */
1408 MOD_ACTION_RETURN, /* userlock */
1409 MOD_ACTION_RETURN, /* notfound */
1410 MOD_ACTION_RETURN, /* noop */
1411 MOD_ACTION_RETURN /* updated */
1415 MOD_ACTION_RETURN, /* reject */
1417 MOD_ACTION_RETURN, /* ok */
1418 MOD_ACTION_RETURN, /* handled */
1419 MOD_ACTION_RETURN, /* invalid */
1420 MOD_ACTION_RETURN, /* userlock */
1422 MOD_ACTION_RETURN, /* noop */
1423 MOD_ACTION_RETURN /* updated */
1430 MOD_ACTION_RETURN, /* reject */
1431 MOD_ACTION_RETURN, /* fail */
1433 MOD_ACTION_RETURN, /* handled */
1434 MOD_ACTION_RETURN, /* invalid */
1435 MOD_ACTION_RETURN, /* userlock */
1442 MOD_ACTION_RETURN, /* reject */
1444 MOD_ACTION_RETURN, /* ok */
1445 MOD_ACTION_RETURN, /* handled */
1446 MOD_ACTION_RETURN, /* invalid */
1447 MOD_ACTION_RETURN, /* userlock */
1448 MOD_ACTION_RETURN, /* notfound */
1449 MOD_ACTION_RETURN, /* noop */
1450 MOD_ACTION_RETURN /* updated */
1454 MOD_ACTION_RETURN, /* reject */
1456 MOD_ACTION_RETURN, /* ok */
1457 MOD_ACTION_RETURN, /* handled */
1458 MOD_ACTION_RETURN, /* invalid */
1459 MOD_ACTION_RETURN, /* userlock */
1461 MOD_ACTION_RETURN, /* noop */
1462 MOD_ACTION_RETURN /* updated */
1469 MOD_ACTION_RETURN, /* reject */
1470 MOD_ACTION_RETURN, /* fail */
1472 MOD_ACTION_RETURN, /* handled */
1473 MOD_ACTION_RETURN, /* invalid */
1474 MOD_ACTION_RETURN, /* userlock */
1481 MOD_ACTION_RETURN, /* reject */
1483 MOD_ACTION_RETURN, /* ok */
1484 MOD_ACTION_RETURN, /* handled */
1485 MOD_ACTION_RETURN, /* invalid */
1486 MOD_ACTION_RETURN, /* userlock */
1487 MOD_ACTION_RETURN, /* notfound */
1488 MOD_ACTION_RETURN, /* noop */
1489 MOD_ACTION_RETURN /* updated */
1493 MOD_ACTION_RETURN, /* reject */
1495 MOD_ACTION_RETURN, /* ok */
1496 MOD_ACTION_RETURN, /* handled */
1497 MOD_ACTION_RETURN, /* invalid */
1498 MOD_ACTION_RETURN, /* userlock */
1500 MOD_ACTION_RETURN, /* noop */
1501 MOD_ACTION_RETURN /* updated */
1510 MOD_ACTION_RETURN, /* reject */
1511 MOD_ACTION_RETURN, /* fail */
1513 MOD_ACTION_RETURN, /* handled */
1514 MOD_ACTION_RETURN, /* invalid */
1515 MOD_ACTION_RETURN, /* userlock */
1522 MOD_ACTION_RETURN, /* reject */
1524 MOD_ACTION_RETURN, /* ok */
1525 MOD_ACTION_RETURN, /* handled */
1526 MOD_ACTION_RETURN, /* invalid */
1527 MOD_ACTION_RETURN, /* userlock */
1528 MOD_ACTION_RETURN, /* notfound */
1529 MOD_ACTION_RETURN, /* noop */
1530 MOD_ACTION_RETURN /* updated */
1534 MOD_ACTION_RETURN, /* reject */
1536 MOD_ACTION_RETURN, /* ok */
1537 MOD_ACTION_RETURN, /* handled */
1538 MOD_ACTION_RETURN, /* invalid */
1539 MOD_ACTION_RETURN, /* userlock */
1541 MOD_ACTION_RETURN, /* noop */
1542 MOD_ACTION_RETURN /* updated */
1549 MOD_ACTION_RETURN, /* reject */
1550 MOD_ACTION_RETURN, /* fail */
1552 MOD_ACTION_RETURN, /* handled */
1553 MOD_ACTION_RETURN, /* invalid */
1554 MOD_ACTION_RETURN, /* userlock */
1561 MOD_ACTION_RETURN, /* reject */
1563 MOD_ACTION_RETURN, /* ok */
1564 MOD_ACTION_RETURN, /* handled */
1565 MOD_ACTION_RETURN, /* invalid */
1566 MOD_ACTION_RETURN, /* userlock */
1567 MOD_ACTION_RETURN, /* notfound */
1568 MOD_ACTION_RETURN, /* noop */
1569 MOD_ACTION_RETURN /* updated */
1573 MOD_ACTION_RETURN, /* reject */
1575 MOD_ACTION_RETURN, /* ok */
1576 MOD_ACTION_RETURN, /* handled */
1577 MOD_ACTION_RETURN, /* invalid */
1578 MOD_ACTION_RETURN, /* userlock */
1580 MOD_ACTION_RETURN, /* noop */
1581 MOD_ACTION_RETURN /* updated */
1587 /** Validate and fixup a map that's part of an update section.
1589 * @param map to validate.
1590 * @param ctx data to pass to fixup function (currently unused).
1591 * @return 0 if valid else -1.
1593 int modcall_fixup_update(value_pair_map_t *map, UNUSED void *ctx)
1595 CONF_PAIR *cp = cf_itemtopair(map->ci);
1598 * Anal-retentive checks.
1600 if (DEBUG_ENABLED2) {
1601 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->name[0] != '&')) {
1602 WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
1603 cf_pair_filename(cp), cf_pair_lineno(cp),
1604 map->lhs->name, fr_int2str(fr_tokens, map->op, "<INVALID>"));
1607 if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->name[0] != '&')) {
1608 WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
1609 cf_pair_filename(cp), cf_pair_lineno(cp),
1610 fr_int2str(fr_tokens, map->op, "<INVALID>"), map->rhs->name);
1615 * Values used by unary operators should be literal ANY
1617 * We then free the template and alloc a NULL one instead.
1619 if (map->op == T_OP_CMP_FALSE) {
1620 if ((map->rhs->type != TMPL_TYPE_LITERAL) || (strcmp(map->rhs->name, "ANY") != 0)) {
1621 WARN("%s[%d] Wildcard deletion MUST use '!* ANY'",
1622 cf_pair_filename(cp), cf_pair_lineno(cp));
1625 tmpl_free(&map->rhs);
1627 map->rhs = tmpl_alloc(map, TMPL_TYPE_NULL, NULL, 0);
1631 * Lots of sanity checks for insane people...
1635 * We don't support implicit type conversion,
1636 * except for "octets"
1638 if (((map->lhs->type == TMPL_TYPE_ATTR) || (map->lhs->type == TMPL_TYPE_DATA)) &&
1639 ((map->rhs->type == TMPL_TYPE_ATTR) || (map->rhs->type == TMPL_TYPE_DATA))) {
1643 switch (map->lhs->type) {
1644 case TMPL_TYPE_ATTR:
1645 lhs_type = map->lhs->tmpl_da->type;
1648 case TMPL_TYPE_DATA:
1649 lhs_type = map->lhs->tmpl_data_type;
1657 switch (map->rhs->type) {
1658 case TMPL_TYPE_ATTR:
1659 rhs_type = map->rhs->tmpl_da->type;
1662 case TMPL_TYPE_DATA:
1663 rhs_type = map->rhs->tmpl_data_type;
1672 if ((lhs_type != rhs_type) &&
1673 (lhs_type != PW_TYPE_OCTETS) &&
1674 (rhs_type != PW_TYPE_OCTETS)) {
1675 cf_log_err(map->ci, "Attribute type mismatch");
1681 * What exactly where you expecting to happen here?
1683 if ((map->lhs->type == TMPL_TYPE_ATTR) &&
1684 (map->rhs->type == TMPL_TYPE_LIST)) {
1685 cf_log_err(map->ci, "Can't copy list into an attribute");
1690 * Depending on the attribute type, some operators are disallowed.
1692 if (map->lhs->type == TMPL_TYPE_ATTR) {
1695 cf_log_err(map->ci, "Invalid operator for attribute");
1704 case T_OP_CMP_FALSE:
1710 if (map->lhs->type == TMPL_TYPE_LIST) {
1712 * Can't copy an xlat expansion or literal into a list,
1713 * we don't know what type of attribute we'd need
1716 * The only exception is where were using a unary
1719 if (map->op != T_OP_CMP_FALSE) switch (map->rhs->type) {
1720 case TMPL_TYPE_XLAT:
1721 case TMPL_TYPE_LITERAL:
1722 cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
1730 * Only += and :=, and !* operators are supported
1734 case T_OP_CMP_FALSE:
1738 if ((map->rhs->type != TMPL_TYPE_LIST) &&
1739 (map->rhs->type != TMPL_TYPE_EXEC)) {
1740 cf_log_err(map->ci, "Invalid source for list assignment '%s += ...'", map->lhs->name);
1746 if (map->rhs->type == TMPL_TYPE_EXEC) {
1747 WARN("%s[%d] Please change ':=' to '=' for list assignment",
1748 cf_pair_filename(cp), cf_pair_lineno(cp));
1751 if (map->rhs->type != TMPL_TYPE_LIST) {
1752 cf_log_err(map->ci, "Invalid source for list assignment '%s := ...'", map->lhs->name);
1758 if (map->rhs->type != TMPL_TYPE_EXEC) {
1759 cf_log_err(map->ci, "Invalid source for list assignment '%s = ...'", map->lhs->name);
1765 cf_log_err(map->ci, "Operator \"%s\" not allowed for list assignment",
1766 fr_int2str(fr_tokens, map->op, "<INVALID>"));
1772 * If the map has a unary operator there's no further
1773 * processing we need to, as RHS is unused.
1775 if (map->op == T_OP_CMP_FALSE) return 0;
1778 * If LHS is an attribute, and RHS is a literal, we can
1779 * preparse the information into a TMPL_TYPE_DATA.
1781 * Unless it's a unary operator in which case we
1784 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->rhs->type == TMPL_TYPE_LITERAL)) {
1786 * It's a literal string, just copy it.
1787 * Don't escape anything.
1789 if (!cf_new_escape &&
1790 (map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
1791 (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
1792 tmpl_cast_in_place_str(map->rhs);
1794 if (!tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da)) {
1795 cf_log_err(map->ci, "%s", fr_strerror());
1800 * Fixup LHS da if it doesn't match the type
1803 if (map->lhs->tmpl_da->type != map->rhs->tmpl_data_type) {
1804 DICT_ATTR const *da;
1806 da = dict_attrbytype(map->lhs->tmpl_da->attr, map->lhs->tmpl_da->vendor,
1807 map->rhs->tmpl_data_type);
1809 fr_strerror_printf("Cannot find %s variant of attribute \"%s\"",
1810 fr_int2str(dict_attr_types, map->rhs->tmpl_data_type,
1811 "<INVALID>"), map->lhs->tmpl_da->name);
1814 map->lhs->tmpl_da = da;
1817 } /* else we can't precompile the data */
1824 static modcallable *do_compile_modupdate(modcallable *parent, UNUSED rlm_components_t component,
1825 CONF_SECTION *cs, char const *name2)
1829 modcallable *csingle;
1831 value_pair_map_t *head;
1834 * This looks at cs->name2 to determine which list to update
1836 rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, modcall_fixup_update, NULL, 128);
1837 if (rcode < 0) return NULL; /* message already printed */
1839 cf_log_err_cs(cs, "'update' sections cannot be empty");
1843 g = talloc_zero(parent, modgroup);
1844 csingle = mod_grouptocallable(g);
1846 csingle->parent = parent;
1847 csingle->next = NULL;
1850 csingle->name = name2;
1854 csingle->type = MOD_UPDATE;
1855 csingle->method = component;
1857 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1858 sizeof(csingle->actions));
1860 g->grouptype = GROUPTYPE_SIMPLE;
1863 g->map = talloc_steal(g, head);
1869 static modcallable *do_compile_modswitch (modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1874 bool had_seen_default = false;
1875 modcallable *csingle;
1878 value_pair_tmpl_t *vpt;
1880 name2 = cf_section_name2(cs);
1882 cf_log_err_cs(cs, "You must specify a variable to switch over for 'switch'");
1886 if (!cf_item_find_next(cs, NULL)) {
1887 cf_log_err_cs(cs, "'switch' statements cannot be empty");
1892 * Create the template. If we fail, AND it's a bare word
1893 * with &Foo-Bar, it MAY be an attribute defined by a
1894 * module. Allow it for now. The pass2 checks below
1897 type = cf_section_name2_type(cs);
1898 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1899 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1900 char *spaces, *text;
1902 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1904 cf_log_err_cs(cs, "Syntax error");
1905 cf_log_err_cs(cs, "%s", name2);
1906 cf_log_err_cs(cs, "%s^ %s", spaces, text);
1908 talloc_free(spaces);
1915 * Otherwise a NULL vpt may refer to an attribute defined
1916 * by a module. That is checked in pass 2.
1920 * Walk through the children of the switch section,
1921 * ensuring that they're all 'case' statements
1923 for (ci = cf_item_find_next(cs, NULL);
1925 ci = cf_item_find_next(cs, ci)) {
1926 CONF_SECTION *subcs;
1929 if (!cf_item_is_section(ci)) {
1930 if (!cf_item_is_pair(ci)) continue;
1932 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1937 subcs = cf_itemtosection(ci); /* can't return NULL */
1938 name1 = cf_section_name1(subcs);
1940 if (strcmp(name1, "case") != 0) {
1941 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1946 name2 = cf_section_name2(subcs);
1948 if (!had_seen_default) {
1949 had_seen_default = true;
1953 cf_log_err(ci, "Cannot have two 'default' case statements");
1959 csingle = do_compile_modgroup(parent, component, cs,
1968 g = mod_callabletogroup(csingle);
1969 g->vpt = talloc_steal(g, vpt);
1974 static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1978 modcallable *csingle;
1980 value_pair_tmpl_t *vpt;
1982 if (!parent || (parent->type != MOD_SWITCH)) {
1983 cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
1988 * case THING means "match THING"
1989 * case means "match anything"
1991 name2 = cf_section_name2(cs);
1996 type = cf_section_name2_type(cs);
1998 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1999 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
2000 char *spaces, *text;
2002 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
2004 cf_log_err_cs(cs, "Syntax error");
2005 cf_log_err_cs(cs, "%s", name2);
2006 cf_log_err_cs(cs, "%s^ %s", spaces, text);
2008 talloc_free(spaces);
2015 * Otherwise a NULL vpt may refer to an attribute defined
2016 * by a module. That is checked in pass 2.
2023 csingle = do_compile_modgroup(parent, component, cs,
2033 * The interpretor expects this to be NULL for the
2034 * default case. do_compile_modgroup sets it to name2,
2035 * unless name2 is NULL, in which case it sets it to name1.
2037 csingle->name = name2;
2039 g = mod_callabletogroup(csingle);
2040 g->vpt = talloc_steal(g, vpt);
2043 * Set all of it's codes to return, so that
2044 * when we pick a 'case' statement, we don't
2045 * fall through to processing the next one.
2047 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2048 csingle->actions[i] = MOD_ACTION_RETURN;
2054 static modcallable *do_compile_modforeach(modcallable *parent,
2055 UNUSED rlm_components_t component, CONF_SECTION *cs)
2059 modcallable *csingle;
2062 value_pair_tmpl_t *vpt;
2064 name2 = cf_section_name2(cs);
2067 "You must specify an attribute to loop over in 'foreach'");
2071 if (!cf_item_find_next(cs, NULL)) {
2072 cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
2077 * Create the template. If we fail, AND it's a bare word
2078 * with &Foo-Bar, it MAY be an attribute defined by a
2079 * module. Allow it for now. The pass2 checks below
2082 type = cf_section_name2_type(cs);
2083 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
2084 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
2085 char *spaces, *text;
2087 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
2089 cf_log_err_cs(cs, "Syntax error");
2090 cf_log_err_cs(cs, "%s", name2);
2091 cf_log_err_cs(cs, "%s^ %s", spaces, text);
2093 talloc_free(spaces);
2099 if (vpt && (vpt->type != TMPL_TYPE_ATTR)) {
2100 cf_log_err_cs(cs, "MUST use attribute reference in 'foreach'");
2105 * Fix up the template to iterate over all instances of
2106 * the attribute. In a perfect consistent world, users would do
2107 * foreach &attr[*], but that's taking the consistency thing a bit far.
2109 if (vpt && (vpt->type == TMPL_TYPE_ATTR)) {
2110 vpt->tmpl_num = NUM_ALL;
2113 csingle = do_compile_modgroup(parent, component, cs,
2114 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2122 g = mod_callabletogroup(csingle);
2128 static modcallable *do_compile_modbreak(modcallable *parent,
2129 rlm_components_t component, CONF_ITEM const *ci)
2131 CONF_SECTION const *cs = NULL;
2133 for (cs = cf_item_parent(ci);
2135 cs = cf_item_parent(cf_sectiontoitem(cs))) {
2136 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
2142 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
2146 return do_compile_modgroup(parent, component, NULL,
2147 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2152 static modcallable *do_compile_modserver(modcallable *parent,
2153 rlm_components_t component, CONF_ITEM *ci,
2158 modcallable *csingle;
2159 CONF_SECTION *subcs;
2162 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
2164 cf_log_err(ci, "Server %s has no %s section",
2165 server, comp2str[component]);
2169 mr = talloc_zero(parent, modref);
2171 csingle = mod_reftocallable(mr);
2172 csingle->parent = parent;
2173 csingle->next = NULL;
2174 csingle->name = name;
2175 csingle->type = MOD_REFERENCE;
2176 csingle->method = component;
2178 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2179 sizeof(csingle->actions));
2181 mr->ref_name = strdup(server);
2187 static modcallable *do_compile_modxlat(modcallable *parent,
2188 rlm_components_t component, char const *fmt)
2190 modcallable *csingle;
2193 mx = talloc_zero(parent, modxlat);
2195 csingle = mod_xlattocallable(mx);
2196 csingle->parent = parent;
2197 csingle->next = NULL;
2198 csingle->name = "expand";
2199 csingle->type = MOD_XLAT;
2200 csingle->method = component;
2202 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2203 sizeof(csingle->actions));
2205 mx->xlat_name = strdup(fmt);
2206 if (fmt[0] != '%') {
2210 strcpy(mx->xlat_name, fmt + 1);
2211 p = strrchr(mx->xlat_name, '`');
2219 * redundant, etc. can refer to modules or groups, but not much else.
2221 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
2225 for (ci=cf_item_find_next(cs, NULL);
2227 ci=cf_item_find_next(cs, ci)) {
2229 * If we're a redundant, etc. group, then the
2230 * intention is to call modules, rather than
2231 * processing logic. These checks aren't
2232 * *strictly* necessary, but they keep the users
2233 * from doing crazy things.
2235 if (cf_item_is_section(ci)) {
2236 CONF_SECTION *subcs = cf_itemtosection(ci);
2237 char const *name1 = cf_section_name1(subcs);
2239 if ((strcmp(name1, "if") == 0) ||
2240 (strcmp(name1, "else") == 0) ||
2241 (strcmp(name1, "elsif") == 0) ||
2242 (strcmp(name1, "update") == 0) ||
2243 (strcmp(name1, "switch") == 0) ||
2244 (strcmp(name1, "case") == 0)) {
2245 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
2252 if (cf_item_is_pair(ci)) {
2253 CONF_PAIR *cp = cf_itemtopair(ci);
2254 if (cf_pair_value(cp) != NULL) {
2256 "Entry with no value is invalid");
2267 * Compile one entry of a module call.
2269 static modcallable *do_compile_modsingle(modcallable *parent,
2270 rlm_components_t component, CONF_ITEM *ci,
2272 char const **modname)
2274 char const *modrefname;
2276 modcallable *csingle;
2277 module_instance_t *this;
2278 CONF_SECTION *cs, *subcs, *modules;
2279 char const *realname;
2281 if (cf_item_is_section(ci)) {
2284 cs = cf_itemtosection(ci);
2285 modrefname = cf_section_name1(cs);
2286 name2 = cf_section_name2(cs);
2287 if (!name2) name2 = "";
2290 * group{}, redundant{}, or append{} may appear
2291 * where a single module instance was expected.
2292 * In that case, we hand it off to
2295 if (strcmp(modrefname, "group") == 0) {
2297 return do_compile_modgroup(parent, component, cs,
2299 grouptype, MOD_GROUP);
2301 } else if (strcmp(modrefname, "redundant") == 0) {
2304 if (!all_children_are_modules(cs, modrefname)) {
2308 return do_compile_modgroup(parent, component, cs,
2309 GROUPTYPE_REDUNDANT,
2310 grouptype, MOD_GROUP);
2312 } else if (strcmp(modrefname, "append") == 0) {
2314 return do_compile_modgroup(parent, component, cs,
2316 grouptype, MOD_GROUP);
2318 } else if (strcmp(modrefname, "load-balance") == 0) {
2321 if (!all_children_are_modules(cs, modrefname)) {
2325 return do_compile_modgroup(parent, component, cs,
2327 grouptype, MOD_LOAD_BALANCE);
2329 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
2332 if (!all_children_are_modules(cs, modrefname)) {
2336 return do_compile_modgroup(parent, component, cs,
2337 GROUPTYPE_REDUNDANT,
2338 grouptype, MOD_REDUNDANT_LOAD_BALANCE);
2341 } else if (strcmp(modrefname, "if") == 0) {
2342 if (!cf_section_name2(cs)) {
2343 cf_log_err(ci, "'if' without condition");
2348 csingle= do_compile_modgroup(parent, component, cs,
2351 if (!csingle) return NULL;
2356 } else if (strcmp(modrefname, "elsif") == 0) {
2358 ((parent->type == MOD_LOAD_BALANCE) ||
2359 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2360 cf_log_err(ci, "'elsif' cannot be used in this section");
2364 if (!cf_section_name2(cs)) {
2365 cf_log_err(ci, "'elsif' without condition");
2370 return do_compile_modgroup(parent, component, cs,
2372 grouptype, MOD_ELSIF);
2374 } else if (strcmp(modrefname, "else") == 0) {
2376 ((parent->type == MOD_LOAD_BALANCE) ||
2377 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2378 cf_log_err(ci, "'else' cannot be used in this section section");
2382 if (cf_section_name2(cs)) {
2383 cf_log_err(ci, "Cannot have conditions on 'else'");
2388 return do_compile_modgroup(parent, component, cs,
2390 grouptype, MOD_ELSE);
2392 } else if (strcmp(modrefname, "update") == 0) {
2395 return do_compile_modupdate(parent, component, cs,
2398 } else if (strcmp(modrefname, "switch") == 0) {
2401 return do_compile_modswitch (parent, component, cs);
2403 } else if (strcmp(modrefname, "case") == 0) {
2406 return do_compile_modcase(parent, component, cs);
2408 } else if (strcmp(modrefname, "foreach") == 0) {
2411 return do_compile_modforeach(parent, component, cs);
2414 } /* else it's something like sql { fail = 1 ...} */
2416 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2420 * Else it's a module reference, with updated return
2425 CONF_PAIR *cp = cf_itemtopair(ci);
2426 modrefname = cf_pair_attr(cp);
2429 * Actions (ok = 1), etc. are orthogonal to just
2430 * about everything else.
2432 if (cf_pair_value(cp) != NULL) {
2433 cf_log_err(ci, "Entry is not a reference to a module");
2437 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2438 (modrefname[0] == '`')) {
2439 return do_compile_modxlat(parent, component,
2444 * See if the module is a virtual one. If so,
2445 * return that, rather than doing anything here.
2448 cs = cf_section_find("instantiate");
2449 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
2452 (cs = cf_section_find("policy")) != NULL) {
2455 snprintf(buffer, sizeof(buffer), "%s.%s",
2456 modrefname, comp2str[component]);
2459 * Prefer name.section, then name.
2461 subcs = cf_section_sub_find_name2(cs, NULL,
2464 subcs = cf_section_sub_find_name2(cs, NULL,
2470 * Allow policies to over-ride module names.
2471 * i.e. the "sql" policy can do some extra things,
2472 * and then call the "sql" module.
2474 for (loop = cf_item_parent(ci);
2476 loop = cf_item_parent(cf_sectiontoitem(loop))) {
2477 if (loop == subcs) {
2484 * redundant foo {} is a single.
2486 if (cf_section_name2(subcs)) {
2487 return do_compile_modsingle(parent,
2489 cf_sectiontoitem(subcs),
2494 * foo {} is a group.
2496 return do_compile_modgroup(parent,
2500 grouptype, MOD_GROUP);
2506 if (strcmp(modrefname, "break") == 0) {
2507 return do_compile_modbreak(parent, component, ci);
2510 if (strcmp(modrefname, "return") == 0) {
2511 return do_compile_modgroup(parent, component, NULL,
2512 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2518 * Not a virtual module. It must be a real module.
2520 modules = cf_section_find("modules");
2522 realname = modrefname;
2526 * Try to load the optional module.
2528 if (realname[0] == '-') realname++;
2531 * As of v3, only known modules are in the
2532 * "modules" section.
2534 if (cf_section_sub_find_name2(modules, NULL, realname)) {
2535 this = find_module_instance(modules, realname, true);
2536 if (!this && (realname != modrefname)) {
2542 * We were asked to MAYBE load it and it
2543 * doesn't exist. Return a soft error.
2545 if (realname != modrefname) {
2546 *modname = modrefname;
2557 * Maybe it's module.method
2559 p = strrchr(modrefname, '.');
2560 if (p) for (i = RLM_COMPONENT_AUTH;
2561 i < RLM_COMPONENT_COUNT;
2563 if (strcmp(p + 1, comp2str[i]) == 0) {
2566 strlcpy(buffer, modrefname, sizeof(buffer));
2567 buffer[p - modrefname] = '\0';
2570 this = find_module_instance(modules, buffer, true);
2571 if (this && !this->entry->module->methods[i]) {
2573 cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
2582 * Call a server. This should really be deleted...
2584 if (strncmp(modrefname, "server[", 7) == 0) {
2587 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2588 p = strrchr(buffer, ']');
2589 if (!p || p[1] != '\0' || (p == buffer)) {
2590 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2595 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2597 cf_log_err(ci, "No such server \"%s\".", buffer);
2601 return do_compile_modserver(parent, component, ci,
2602 modrefname, cs, buffer);
2606 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
2607 cf_log_err(ci, "Please verify that the configuration exists in the file %s/mods-enabled/%s.", get_radius_dir(), modrefname);
2612 * We know it's all OK, allocate the structures, and fill
2615 single = talloc_zero(parent, modsingle);
2616 csingle = mod_singletocallable(single);
2617 csingle->parent = parent;
2618 csingle->next = NULL;
2619 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2620 memcpy(csingle->actions, defaultactions[component][grouptype],
2621 sizeof csingle->actions);
2622 } else { /* inside Auth-Type has different rules */
2623 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2624 sizeof csingle->actions);
2626 rad_assert(modrefname != NULL);
2627 csingle->name = realname;
2628 csingle->type = MOD_SINGLE;
2629 csingle->method = component;
2632 * Singles can override the actions, virtual modules cannot.
2634 * FIXME: We may want to re-visit how to do this...
2635 * maybe a csingle as a ref?
2637 if (cf_item_is_section(ci)) {
2640 cs = cf_itemtosection(ci);
2641 for (csi=cf_item_find_next(cs, NULL);
2643 csi=cf_item_find_next(cs, csi)) {
2645 if (cf_item_is_section(csi)) {
2646 cf_log_err(csi, "Subsection of module instance call not allowed");
2647 talloc_free(csingle);
2651 if (!cf_item_is_pair(csi)) continue;
2653 if (!compile_action(csingle, cf_itemtopair(csi))) {
2654 talloc_free(csingle);
2661 * Bail out if the module in question does not supply the
2664 if (!this->entry->module->methods[component]) {
2665 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2666 comp2str[component]);
2667 talloc_free(csingle);
2671 single->modinst = this;
2672 *modname = this->entry->module->name;
2676 modcallable *compile_modsingle(TALLOC_CTX *ctx,
2677 modcallable **parent,
2678 rlm_components_t component, CONF_ITEM *ci,
2679 char const **modname)
2686 CONF_SECTION *parentcs;
2688 g = talloc_zero(ctx, modgroup);
2689 memset(g, 0, sizeof(*g));
2690 g->grouptype = GROUPTYPE_SIMPLE;
2691 c = mod_grouptocallable(g);
2694 defaultactions[component][GROUPTYPE_SIMPLE],
2695 sizeof(c->actions));
2697 parentcs = cf_item_parent(ci);
2698 c->name = cf_section_name2(parentcs);
2700 c->name = cf_section_name1(parentcs);
2703 c->type = MOD_GROUP;
2704 c->method = component;
2707 *parent = mod_grouptocallable(g);
2710 ret = do_compile_modsingle(*parent, component, ci,
2713 dump_tree(component, ret);
2719 * Internal compile group code.
2721 static modcallable *do_compile_modgroup(modcallable *parent,
2722 rlm_components_t component, CONF_SECTION *cs,
2723 int grouptype, int parentgrouptype, int mod_type)
2730 g = talloc_zero(parent, modgroup);
2731 g->grouptype = grouptype;
2735 c = mod_grouptocallable(g);
2739 memset(c->actions, 0, sizeof(c->actions));
2741 if (!cs) { /* only for "break" and "return" */
2747 * Remember the name for printing, etc.
2749 * FIXME: We may also want to put the names into a
2750 * rbtree, so that groups can reference each other...
2752 c->name = cf_section_name2(cs);
2754 c->name = cf_section_name1(cs);
2755 if ((strcmp(c->name, "group") == 0) ||
2756 (strcmp(c->name, "redundant") == 0)) {
2758 } else if (c->type == MOD_GROUP) {
2759 c->type = MOD_POLICY;
2765 * Do load-time optimizations
2767 if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
2770 rad_assert(parent != NULL);
2772 if (c->type == MOD_IF) {
2773 g->cond = cf_data_find(g->cs, "if");
2774 rad_assert(g->cond != NULL);
2777 if (g->cond->type == COND_TYPE_FALSE) {
2778 INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
2779 group_name[g->mc.type],
2780 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2784 } else if (c->type == MOD_ELSIF) {
2786 g->cond = cf_data_find(g->cs, "if");
2787 rad_assert(g->cond != NULL);
2789 rad_assert(parent != NULL);
2790 p = mod_callabletogroup(parent);
2792 rad_assert(p->tail != NULL);
2794 f = mod_callabletogroup(p->tail);
2795 rad_assert((f->mc.type == MOD_IF) ||
2796 (f->mc.type == MOD_ELSIF));
2799 * If we took the previous condition, we
2800 * don't need to take this one.
2802 * We reset our condition to 'true', so
2803 * that subsequent sections can check
2804 * that they don't need to be executed.
2806 if (f->cond->type == COND_TYPE_TRUE) {
2808 INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
2809 group_name[g->mc.type],
2810 group_name[f->mc.type],
2811 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2818 rad_assert(c->type == MOD_ELSE);
2820 rad_assert(parent != NULL);
2821 p = mod_callabletogroup(parent);
2823 rad_assert(p->tail != NULL);
2825 f = mod_callabletogroup(p->tail);
2826 rad_assert((f->mc.type == MOD_IF) ||
2827 (f->mc.type == MOD_ELSIF));
2830 * If we took the previous condition, we
2831 * don't need to take this one.
2833 if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
2837 * Else we need to compile this section
2843 * Loop over the children of this group.
2845 for (ci=cf_item_find_next(cs, NULL);
2847 ci=cf_item_find_next(cs, ci)) {
2850 * Sections are references to other groups, or
2851 * to modules with updated return codes.
2853 if (cf_item_is_section(ci)) {
2854 char const *junk = NULL;
2855 modcallable *single;
2856 CONF_SECTION *subcs = cf_itemtosection(ci);
2858 single = do_compile_modsingle(c, component, ci,
2861 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2862 cf_section_name1(subcs));
2866 add_child(g, single);
2868 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2872 char const *attr, *value;
2873 CONF_PAIR *cp = cf_itemtopair(ci);
2875 attr = cf_pair_attr(cp);
2876 value = cf_pair_value(cp);
2879 * A CONF_PAIR is either a module
2880 * instance with no actions
2884 modcallable *single;
2885 char const *junk = NULL;
2887 single = do_compile_modsingle(c,
2893 if (cf_item_is_pair(ci) &&
2894 cf_pair_attr(cf_itemtopair(ci))[0] == '-') {
2899 "Failed to parse \"%s\" entry.",
2904 add_child(g, single);
2907 * Or a module instance with action.
2909 } else if (!compile_action(c, cp)) {
2912 } /* else it worked */
2918 * Set the default actions, if they haven't already been
2921 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2922 if (!c->actions[i]) {
2923 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2924 c->actions[i] = defaultactions[component][parentgrouptype][i];
2925 } else { /* inside Auth-Type has different rules */
2926 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2936 if (grouptype != GROUPTYPE_REDUNDANT) break;
2939 case MOD_LOAD_BALANCE:
2940 case MOD_REDUNDANT_LOAD_BALANCE:
2942 cf_log_err_cs(g->cs, "%s sections cannot be empty",
2943 cf_section_name1(g->cs));
2950 * FIXME: If there are no children, return NULL?
2952 return mod_grouptocallable(g);
2955 modcallable *compile_modgroup(modcallable *parent,
2956 rlm_components_t component, CONF_SECTION *cs)
2958 modcallable *ret = do_compile_modgroup(parent, component, cs,
2960 GROUPTYPE_SIMPLE, MOD_GROUP);
2962 if (debug_flag > 3) {
2963 modcall_debug(ret, 2);
2969 void add_to_modcallable(modcallable *parent, modcallable *this)
2973 rad_assert(this != NULL);
2974 rad_assert(parent != NULL);
2976 g = mod_callabletogroup(parent);
2983 static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t **pvpt, bool convert,
2984 DICT_ATTR const *da)
2990 value_pair_tmpl_t *vpt;
2994 rad_assert(vpt->type == TMPL_TYPE_XLAT);
2996 fmt = talloc_typed_strdup(vpt, vpt->name);
2997 slen = xlat_tokenize(vpt, fmt, &head, &error);
3000 char *spaces, *text;
3002 fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
3004 cf_log_err(ci, "Failed parsing expanded string:");
3005 cf_log_err(ci, "%s", text);
3006 cf_log_err(ci, "%s^ %s", spaces, error);
3008 talloc_free(spaces);
3014 * Convert %{Attribute-Name} to &Attribute-Name
3017 value_pair_tmpl_t *attr;
3019 attr = xlat_to_tmpl_attr(talloc_parent(vpt), head);
3022 * If it's a virtual attribute, leave it
3025 if (attr->tmpl_da->flags.virtual) {
3031 * If the attribute is of incompatible
3032 * type, leave it alone.
3034 if (da && (da->type != attr->tmpl_da->type)) {
3039 if (cf_item_is_pair(ci)) {
3040 CONF_PAIR *cp = cf_itemtopair(ci);
3042 WARN("%s[%d] Please change %%{%s} to &%s",
3043 cf_pair_filename(cp), cf_pair_lineno(cp),
3044 attr->name, attr->name);
3046 CONF_SECTION *cs = cf_itemtosection(ci);
3048 WARN("%s[%d] Please change %%{%s} to &%s",
3049 cf_section_filename(cs), cf_section_lineno(cs),
3050 attr->name, attr->name);
3059 * Re-write it to be a pre-parsed XLAT structure.
3061 vpt->type = TMPL_TYPE_XLAT_STRUCT;
3062 vpt->tmpl_xlat = head;
3069 static int _free_compiled_regex(regex_t *preg)
3075 static bool pass2_regex_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
3080 rad_assert(vpt->type == TMPL_TYPE_REGEX);
3083 * It's a dynamic expansion. We can't expand the string,
3084 * but we can pre-parse it as an xlat struct. In that
3085 * case, we convert it to a pre-compiled XLAT.
3087 * This is a little more complicated than it needs to be
3088 * because radius_evaluate_map() keys off of the src
3089 * template type, instead of the operators. And, the
3090 * pass2_xlat_compile() function expects to get passed an
3091 * XLAT instead of a REGEX.
3093 if (strchr(vpt->name, '%')) {
3094 vpt->type = TMPL_TYPE_XLAT;
3095 return pass2_xlat_compile(ci, &vpt, false, NULL);
3098 preg = talloc_zero(vpt, regex_t);
3099 talloc_set_destructor(preg, _free_compiled_regex);
3100 if (!preg) return false;
3102 rcode = regcomp(preg, vpt->name, REG_EXTENDED | (vpt->tmpl_iflag ? REG_ICASE : 0));
3105 regerror(rcode, preg, buffer, sizeof(buffer));
3107 cf_log_err(ci, "Invalid regular expression %s: %s",
3112 vpt->type = TMPL_TYPE_REGEX_STRUCT;
3113 vpt->tmpl_preg = preg;
3119 static bool pass2_fixup_undefined(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
3121 DICT_ATTR const *da;
3123 rad_assert(vpt->type == TMPL_TYPE_ATTR_UNDEFINED);
3125 da = dict_attrbyname(vpt->tmpl_unknown_name);
3127 cf_log_err(ci, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
3132 vpt->type = TMPL_TYPE_ATTR;
3136 /** Convert an &attr[*] reference to an XLAT
3138 * @param vpt to convert
3139 * @return true if conversion was successful, else false.
3141 static bool pass2_fixup_attr_count(value_pair_tmpl_t *vpt)
3145 rad_assert(vpt->type == TMPL_TYPE_ATTR);
3146 rad_assert(vpt->tmpl_num == NUM_COUNT);
3148 node = xlat_from_tmpl_attr(vpt, vpt);
3149 if (!node) return false;
3151 memset(&vpt->data, 0, sizeof(vpt->data));
3152 vpt->type = TMPL_TYPE_XLAT_STRUCT;
3153 vpt->data.xlat = node;
3158 static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
3160 value_pair_map_t *map;
3162 if (c->type == COND_TYPE_EXISTS) {
3163 if (c->data.vpt->type == TMPL_TYPE_XLAT) {
3164 return pass2_xlat_compile(c->ci, &c->data.vpt, true, NULL);
3167 rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
3170 * The existence check might have been &Foo-Bar,
3171 * where Foo-Bar is defined by a module.
3173 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3174 if (!pass2_fixup_undefined(c->ci, c->data.vpt)) return false;
3175 c->pass2_fixup = PASS2_FIXUP_NONE;
3178 if ((c->data.vpt->type == TMPL_TYPE_ATTR) && (c->data.vpt->tmpl_num == NUM_COUNT)) {
3179 return pass2_fixup_attr_count(c->data.vpt);
3185 * Maps have a paircompare fixup applied to them.
3186 * Others get ignored.
3188 if (c->pass2_fixup == PASS2_FIXUP_NONE) {
3189 if (c->type == COND_TYPE_MAP) {
3197 map = c->data.map; /* shorter */
3202 * Where "foo" is dynamically defined.
3204 if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
3205 if (!dict_valbyname(map->lhs->tmpl_da->attr,
3206 map->lhs->tmpl_da->vendor,
3208 cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
3209 map->lhs->tmpl_da->name,
3215 * These guys can't have a paircompare fixup applied.
3217 c->pass2_fixup = PASS2_FIXUP_NONE;
3221 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3222 if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3223 if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
3226 if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3227 if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
3230 c->pass2_fixup = PASS2_FIXUP_NONE;
3235 * Just in case someone adds a new fixup later.
3237 rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
3238 (c->pass2_fixup == PASS2_PAIRCOMPARE));
3240 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->tmpl_num == NUM_COUNT)) {
3241 if (!pass2_fixup_attr_count(map->lhs)) return false;
3243 if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->tmpl_num == NUM_COUNT)) {
3244 if (!pass2_fixup_attr_count(map->rhs)) return false;
3250 if (map->lhs->type == TMPL_TYPE_XLAT) {
3252 * Don't compile the LHS to an attribute
3253 * reference for now. When we do that, we've got
3254 * to check the RHS for type-specific data, and
3255 * parse it to a TMPL_TYPE_DATA.
3257 if (!pass2_xlat_compile(map->ci, &map->lhs, false, NULL)) {
3262 if (map->rhs->type == TMPL_TYPE_XLAT) {
3264 * Convert the RHS to an attribute reference only
3265 * if the LHS is an attribute reference, AND is
3266 * of the same type as the RHS.
3268 * We can fix this when the code in evaluate.c
3269 * can handle strings on the LHS, and attributes
3270 * on the RHS. For now, the code in parser.c
3273 if (map->lhs->type == TMPL_TYPE_ATTR) {
3274 DICT_ATTR const *da = c->cast;
3276 if (!c->cast) da = map->lhs->tmpl_da;
3278 if (!pass2_xlat_compile(map->ci, &map->rhs, true, da)) {
3283 if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3290 * Convert bare refs to %{Foreach-Variable-N}
3292 if ((map->lhs->type == TMPL_TYPE_LITERAL) &&
3293 (strncmp(map->lhs->name, "Foreach-Variable-", 17) == 0)) {
3296 value_pair_tmpl_t *vpt;
3298 fmt = talloc_asprintf(map->lhs, "%%{%s}", map->lhs->name);
3299 slen = tmpl_afrom_str(map, &vpt, fmt, talloc_array_length(fmt) - 1,
3300 T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
3302 char *spaces, *text;
3304 fr_canonicalize_error(map->ci, &spaces, &text, slen, fr_strerror());
3306 cf_log_err(map->ci, "Failed converting %s to xlat", map->lhs->name);
3307 cf_log_err(map->ci, "%s", fmt);
3308 cf_log_err(map->ci, "%s^ %s", spaces, text);
3310 talloc_free(spaces);
3316 talloc_free(map->lhs);
3321 if (map->rhs->type == TMPL_TYPE_REGEX) {
3322 if (!pass2_regex_compile(map->ci, map->rhs)) {
3326 rad_assert(map->lhs->type != TMPL_TYPE_REGEX);
3330 * Only attributes can have a paircompare registered, and
3331 * they can only be with the current REQUEST, and only
3332 * with the request pairs.
3334 if ((map->lhs->type != TMPL_TYPE_ATTR) ||
3335 (map->lhs->tmpl_request != REQUEST_CURRENT) ||
3336 (map->lhs->tmpl_list != PAIR_LIST_REQUEST)) {
3340 if (!radius_find_compare(map->lhs->tmpl_da)) return true;
3342 if (map->rhs->type == TMPL_TYPE_ATTR) {
3343 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
3348 if (map->rhs->type == TMPL_TYPE_REGEX) {
3349 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
3355 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
3360 if (map->op != T_OP_CMP_EQ) {
3361 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
3367 * Mark it as requiring a paircompare() call, instead of
3370 c->pass2_fixup = PASS2_PAIRCOMPARE;
3377 * Compile the RHS of update sections to xlat_exp_t
3379 static bool modcall_pass2_update(modgroup *g)
3381 value_pair_map_t *map;
3383 for (map = g->map; map != NULL; map = map->next) {
3384 if (map->rhs->type == TMPL_TYPE_XLAT) {
3385 rad_assert(map->rhs->tmpl_xlat == NULL);
3388 * FIXME: compile to attribute && handle
3389 * the conversion in map_to_vp().
3391 if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3396 rad_assert(map->rhs->type != TMPL_TYPE_REGEX);
3404 * Do a second-stage pass on compiling the modules.
3406 bool modcall_pass2(modcallable *mc)
3413 for (c = mc; c != NULL; c = c->next) {
3421 g = mod_callabletogroup(c);
3422 if (g->done_pass2) return true;
3424 name2 = cf_section_name2(g->cs);
3426 c->debug_name = group_name[c->type];
3428 c->debug_name = talloc_asprintf(c, "update %s", name2);
3431 if (!modcall_pass2_update(g)) {
3434 g->done_pass2 = true;
3437 case MOD_XLAT: /* @todo: pre-parse xlat's */
3444 c->debug_name = c->name;
3445 break; /* do nothing */
3450 g = mod_callabletogroup(c);
3451 if (g->done_pass2) return true;
3453 name2 = cf_section_name2(g->cs);
3454 c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3457 * Don't walk over these.
3459 if ((g->cond->type == COND_TYPE_TRUE) ||
3460 (g->cond->type == COND_TYPE_FALSE)) {
3465 * The compilation code takes care of
3466 * simplifying 'true' and 'false'
3467 * conditions. For others, we have to do
3468 * a second pass to parse && compile xlats.
3470 if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
3474 if (!modcall_pass2(g->children)) return false;
3475 g->done_pass2 = true;
3481 g = mod_callabletogroup(c);
3482 if (g->done_pass2) return true;
3484 name2 = cf_section_name2(g->cs);
3485 c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3488 * We had &Foo-Bar, where Foo-Bar is
3489 * defined by a module.
3492 rad_assert(c->name != NULL);
3493 rad_assert(c->name[0] == '&');
3494 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3496 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3497 cf_section_name2_type(g->cs),
3498 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3500 char *spaces, *text;
3503 fr_canonicalize_error(g->cs, &spaces, &text, slen, fr_strerror());
3505 cf_log_err_cs(g->cs, "Syntax error");
3506 cf_log_err_cs(g->cs, "%s", c->name);
3507 cf_log_err_cs(g->cs, "%s^ %s", spaces, text);
3509 talloc_free(spaces);
3519 * Statically compile xlats
3521 if (g->vpt->type == TMPL_TYPE_XLAT) {
3522 if (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3523 &g->vpt, true, NULL)) {
3531 * We may have: switch Foo-Bar {
3533 * where Foo-Bar is an attribute defined
3534 * by a module. Since there's no leading
3535 * &, it's parsed as a literal. But if
3536 * we can parse it as an attribute,
3537 * switch to using that.
3539 if (g->vpt->type == TMPL_TYPE_LITERAL) {
3540 value_pair_tmpl_t *vpt;
3542 slen = tmpl_afrom_str(g->cs, &vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3543 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3544 if (slen < 0) goto parse_error;
3545 if (vpt->type == TMPL_TYPE_ATTR) {
3546 talloc_free(g->vpt);
3554 * Warn about old-style configuration.
3556 * DEPRECATED: switch User-Name { ...
3557 * ALLOWED : switch &User-Name { ...
3559 if ((g->vpt->type == TMPL_TYPE_ATTR) &&
3560 (c->name[0] != '&')) {
3561 WARN("%s[%d]: Please change %s to &%s",
3562 cf_section_filename(g->cs),
3563 cf_section_lineno(g->cs),
3568 if (!modcall_pass2(g->children)) return false;
3569 g->done_pass2 = true;
3573 g = mod_callabletogroup(c);
3574 if (g->done_pass2) return true;
3576 name2 = cf_section_name2(g->cs);
3578 c->debug_name = group_name[c->type];
3580 c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3583 rad_assert(c->parent != NULL);
3584 rad_assert(c->parent->type == MOD_SWITCH);
3587 * The statement may refer to an
3588 * attribute which doesn't exist until
3589 * all of the modules have been loaded.
3590 * Check for that now.
3592 if (!g->vpt && c->name &&
3593 (c->name[0] == '&') &&
3594 (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
3595 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3596 cf_section_name2_type(g->cs),
3597 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3598 if (slen < 0) goto parse_error;
3602 * We have "case {...}". There's no
3603 * argument, so we don't need to check
3606 if (!g->vpt) goto do_children;
3609 * Do type-specific checks on the case statement
3611 if (g->vpt->type == TMPL_TYPE_LITERAL) {
3614 f = mod_callabletogroup(mc->parent);
3615 rad_assert(f->vpt != NULL);
3618 * We're switching over an
3619 * attribute. Check that the
3622 if (f->vpt->type == TMPL_TYPE_ATTR) {
3623 rad_assert(f->vpt->tmpl_da != NULL);
3625 if (!tmpl_cast_in_place(g->vpt, f->vpt->tmpl_da->type, f->vpt->tmpl_da)) {
3626 cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
3636 * Compile and sanity check xlat
3639 if (g->vpt->type == TMPL_TYPE_XLAT) {
3642 f = mod_callabletogroup(mc->parent);
3643 rad_assert(f->vpt != NULL);
3646 * Don't expand xlat's into an
3647 * attribute of a different type.
3649 if (f->vpt->type == TMPL_TYPE_ATTR) {
3650 if (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3651 &g->vpt, true, f->vpt->tmpl_da)) {
3655 if (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3656 &g->vpt, true, NULL)) {
3662 if (!modcall_pass2(g->children)) return false;
3663 g->done_pass2 = true;
3667 g = mod_callabletogroup(c);
3668 if (g->done_pass2) return true;
3670 name2 = cf_section_name2(g->cs);
3671 c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3674 * Already parsed, handle the children.
3676 if (g->vpt) goto check_children;
3679 * We had &Foo-Bar, where Foo-Bar is
3680 * defined by a module.
3682 rad_assert(c->name != NULL);
3683 rad_assert(c->name[0] == '&');
3684 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3687 * The statement may refer to an
3688 * attribute which doesn't exist until
3689 * all of the modules have been loaded.
3690 * Check for that now.
3692 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3693 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3694 if (slen < 0) goto parse_error;
3697 rad_assert(g->vpt->type == TMPL_TYPE_ATTR);
3698 if (g->vpt->tmpl_num != NUM_ALL) {
3699 cf_log_err_cs(g->cs, "MUST NOT use instance selectors in 'foreach'");
3702 if (!modcall_pass2(g->children)) return false;
3703 g->done_pass2 = true;
3707 c->debug_name = group_name[c->type];
3711 g = mod_callabletogroup(c);
3712 c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], cf_section_name1(g->cs));
3717 case MOD_LOAD_BALANCE:
3718 case MOD_REDUNDANT_LOAD_BALANCE:
3719 c->debug_name = group_name[c->type];
3724 g = mod_callabletogroup(c);
3726 c->debug_name = mc->name; /* for authorize, etc. */
3728 } else if (c->type == MOD_GROUP) { /* for Auth-Type, etc. */
3729 char const *name1 = cf_section_name1(g->cs);
3731 if (strcmp(name1, group_name[c->type]) != 0) {
3732 c->debug_name = talloc_asprintf(c, "%s %s", name1, cf_section_name2(g->cs));
3736 if (g->done_pass2) return true;
3737 if (!modcall_pass2(g->children)) return false;
3738 g->done_pass2 = true;
3746 void modcall_debug(modcallable *mc, int depth)
3750 value_pair_map_t *map;
3753 for (this = mc; this != NULL; this = this->next) {
3754 switch (this->type) {
3759 modsingle *single = mod_callabletosingle(this);
3761 DEBUG("%.*s%s", depth, modcall_spaces,
3762 single->modinst->name);
3768 g = mod_callabletogroup(this);
3769 DEBUG("%.*s%s {", depth, modcall_spaces,
3770 group_name[this->type]);
3772 for (map = g->map; map != NULL; map = map->next) {
3773 map_prints(buffer, sizeof(buffer), map);
3774 DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
3777 DEBUG("%.*s}", depth, modcall_spaces);
3781 g = mod_callabletogroup(this);
3782 DEBUG("%.*s%s {", depth, modcall_spaces,
3783 group_name[this->type]);
3784 modcall_debug(g->children, depth + 1);
3785 DEBUG("%.*s}", depth, modcall_spaces);
3790 g = mod_callabletogroup(this);
3791 fr_cond_sprint(buffer, sizeof(buffer), g->cond);
3792 DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
3793 group_name[this->type], buffer);
3794 modcall_debug(g->children, depth + 1);
3795 DEBUG("%.*s}", depth, modcall_spaces);
3800 g = mod_callabletogroup(this);
3801 tmpl_prints(buffer, sizeof(buffer), g->vpt, NULL);
3802 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3803 group_name[this->type], buffer);
3804 modcall_debug(g->children, depth + 1);
3805 DEBUG("%.*s}", depth, modcall_spaces);
3810 g = mod_callabletogroup(this);
3811 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3812 group_name[this->type], this->name);
3813 modcall_debug(g->children, depth + 1);
3814 DEBUG("%.*s}", depth, modcall_spaces);
3818 DEBUG("%.*sbreak", depth, modcall_spaces);
3823 g = mod_callabletogroup(this);
3824 DEBUG("%.*s%s {", depth, modcall_spaces,
3825 group_name[this->type]);
3826 modcall_debug(g->children, depth + 1);
3827 DEBUG("%.*s}", depth, modcall_spaces);
3831 case MOD_LOAD_BALANCE:
3832 case MOD_REDUNDANT_LOAD_BALANCE:
3833 g = mod_callabletogroup(this);
3834 DEBUG("%.*s%s {", depth, modcall_spaces,
3835 group_name[this->type]);
3836 modcall_debug(g->children, depth + 1);
3837 DEBUG("%.*s}", depth, modcall_spaces);