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 */
72 } grouptype; /* after mc */
73 modcallable *children;
74 modcallable *tail; /* of the children list */
76 vp_map_t *map; /* update */
77 vp_tmpl_t *vpt; /* switch */
78 fr_cond_t *cond; /* if/elsif */
84 module_instance_t *modinst;
99 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
100 * so we often want to go back and forth between them. */
101 static modsingle *mod_callabletosingle(modcallable *p)
103 rad_assert(p->type==MOD_SINGLE);
104 return (modsingle *)p;
106 static modgroup *mod_callabletogroup(modcallable *p)
108 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
110 return (modgroup *)p;
112 static modcallable *mod_singletocallable(modsingle *p)
114 return (modcallable *)p;
116 static modcallable *mod_grouptocallable(modgroup *p)
118 return (modcallable *)p;
121 static modref *mod_callabletoref(modcallable *p)
123 rad_assert(p->type==MOD_REFERENCE);
126 static modcallable *mod_reftocallable(modref *p)
128 return (modcallable *)p;
131 static modxlat *mod_callabletoxlat(modcallable *p)
133 rad_assert(p->type==MOD_XLAT);
136 static modcallable *mod_xlattocallable(modxlat *p)
138 return (modcallable *)p;
141 /* modgroups are grown by adding a modcallable to the end */
142 static void add_child(modgroup *g, modcallable *c)
146 (void) talloc_steal(g, c);
149 g->children = g->tail = c;
151 rad_assert(g->tail->next == NULL);
156 c->parent = mod_grouptocallable(g);
159 /* Here's where we recognize all of our keywords: first the rcodes, then the
161 const FR_NAME_NUMBER mod_rcode_table[] = {
162 { "reject", RLM_MODULE_REJECT },
163 { "fail", RLM_MODULE_FAIL },
164 { "ok", RLM_MODULE_OK },
165 { "handled", RLM_MODULE_HANDLED },
166 { "invalid", RLM_MODULE_INVALID },
167 { "userlock", RLM_MODULE_USERLOCK },
168 { "notfound", RLM_MODULE_NOTFOUND },
169 { "noop", RLM_MODULE_NOOP },
170 { "updated", RLM_MODULE_UPDATED },
176 * Compile action && rcode for later use.
178 static int compile_action(modcallable *c, CONF_PAIR *cp)
181 char const *attr, *value;
183 attr = cf_pair_attr(cp);
184 value = cf_pair_value(cp);
185 if (!value) return 0;
187 if (!strcasecmp(value, "return"))
188 action = MOD_ACTION_RETURN;
190 else if (!strcasecmp(value, "break"))
191 action = MOD_ACTION_RETURN;
193 else if (!strcasecmp(value, "reject"))
194 action = MOD_ACTION_REJECT;
196 else if (strspn(value, "0123456789")==strlen(value)) {
197 action = atoi(value);
200 * Don't allow priority zero, for future use.
202 if (action == 0) return 0;
204 cf_log_err_cp(cp, "Unknown action '%s'.\n",
209 if (strcasecmp(attr, "default") != 0) {
212 rcode = fr_str2int(mod_rcode_table, attr, -1);
215 "Unknown module rcode '%s'.\n",
219 c->actions[rcode] = action;
221 } else { /* set all unset values to the default */
224 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
225 if (!c->actions[i]) c->actions[i] = action;
232 /* Some short names for debugging output */
233 static char const * const comp2str[] = {
249 #ifdef HAVE_PTHREAD_H
251 * Lock the mutex for the module
253 static void safe_lock(module_instance_t *instance)
256 pthread_mutex_lock(instance->mutex);
260 * Unlock the mutex for the module
262 static void safe_unlock(module_instance_t *instance)
265 pthread_mutex_unlock(instance->mutex);
269 * No threads: these functions become NULL's.
271 #define safe_lock(foo)
272 #define safe_unlock(foo)
275 static rlm_rcode_t CC_HINT(nonnull) call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
278 int indent = request->log.indent;
281 * If the request should stop, refuse to do anything.
283 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
284 if (blocked) return RLM_MODULE_NOOP;
286 RDEBUG3("modsingle[%s]: calling %s (%s)",
287 comp2str[component], sp->modinst->name,
288 sp->modinst->entry->name);
289 request->log.indent = 0;
291 if (sp->modinst->force) {
292 request->rcode = sp->modinst->code;
297 * For logging unresponsive children.
299 request->module = sp->modinst->name;
301 safe_lock(sp->modinst);
302 request->rcode = sp->modinst->entry->module->methods[component](sp->modinst->insthandle, request);
303 safe_unlock(sp->modinst);
305 request->module = "";
308 * Wasn't blocked, and now is. Complain!
310 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
312 RWARN("Module %s became unblocked", sp->modinst->entry->name);
316 request->log.indent = indent;
317 RDEBUG3("modsingle[%s]: returned from %s (%s)",
318 comp2str[component], sp->modinst->name,
319 sp->modinst->entry->name);
321 return request->rcode;
324 static int default_component_results[MOD_COUNT] = {
325 RLM_MODULE_REJECT, /* AUTH */
326 RLM_MODULE_NOTFOUND, /* AUTZ */
327 RLM_MODULE_NOOP, /* PREACCT */
328 RLM_MODULE_NOOP, /* ACCT */
329 RLM_MODULE_FAIL, /* SESS */
330 RLM_MODULE_NOOP, /* PRE_PROXY */
331 RLM_MODULE_NOOP, /* POST_PROXY */
332 RLM_MODULE_NOOP /* POST_AUTH */
335 RLM_MODULE_NOOP, /* RECV_COA_TYPE */
336 RLM_MODULE_NOOP /* SEND_COA_TYPE */
341 extern char const *unlang_keyword[];
343 char const *unlang_keyword[] = {
347 "load-balance group",
348 "redundant-load-balance group",
366 static char const modcall_spaces[] = " ";
368 #define MODCALL_STACK_MAX (32)
371 * Don't call the modules recursively. Instead, do them
372 * iteratively, and manage the call stack ourselves.
374 typedef struct modcall_stack_entry_t {
377 int unwind; /* unwind to this one if it exists */
379 } modcall_stack_entry_t;
382 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
383 modcall_stack_entry_t *entry, bool do_next_sibling);
386 * Call a child of a block.
388 static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
389 modcall_stack_entry_t *entry, modcallable *c,
390 rlm_rcode_t *result, bool do_next_sibling)
392 modcall_stack_entry_t *next;
394 if (depth >= MODCALL_STACK_MAX) {
395 ERROR("Internal sanity check failed: module stack is too deep");
400 * Initialize the childs stack frame.
404 next->result = entry->result;
408 if (!modcall_recurse(request, component,
409 depth, next, do_next_sibling)) {
410 *result = RLM_MODULE_FAIL;
415 * Unwind back up the stack
417 if (next->unwind != 0) {
418 entry->unwind = next->unwind;
421 *result = next->result;
428 * Interpret the various types of blocks.
430 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
431 modcall_stack_entry_t *entry, bool do_next_sibling)
433 bool if_taken, was_if;
438 was_if = if_taken = false;
439 result = RLM_MODULE_UNKNOWN;
447 * Nothing more to do. Return the code and priority
448 * which was set by the caller.
452 if (fr_debug_lvl >= 3) {
453 VERIFY_REQUEST(request);
456 rad_assert(c->debug_name != NULL); /* if this happens, all bets are off. */
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{", unlang_keyword[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",
489 unlang_keyword[c->type],
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: Preceding \"if\" was taken",
522 unlang_keyword[c->type]);
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: No preceding \"if\"",
541 unlang_keyword[c->type]);
546 RDEBUG2("... skipping %s: Preceding \"if\" was taken",
547 unlang_keyword[c->type]);
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);
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, (void *)radius_get_vp, i)) {
636 if (foreach_depth < 0) {
637 REDEBUG("foreach Nesting too deep!");
638 result = RLM_MODULE_FAIL;
639 goto calculate_result;
643 * Copy the VPs from the original request, this ensures deterministic
644 * behaviour if someone decides to add or remove VPs in the set were
647 if (tmpl_copy_vps(request, &vps, request, g->vpt) < 0) { /* nothing to loop over */
649 result = RLM_MODULE_NOOP;
651 goto calculate_result;
654 rad_assert(vps != NULL);
655 fr_cursor_init(©, &vps);
657 RDEBUG2("foreach %s ", c->name);
660 * This is the actual body of the foreach loop
662 for (vp = fr_cursor_first(©);
664 vp = fr_cursor_next(©)) {
666 if (fr_debug_lvl >= 2) {
669 vp_prints_value(buffer, sizeof(buffer), vp, '"');
670 RDEBUG2("# Foreach-Variable-%d = %s", foreach_depth, buffer);
675 * Add the vp to the request, so that
676 * xlat.c, xlat_foreach() can find it.
678 request_data_add(request, (void *)radius_get_vp, foreach_depth, &vp, false);
681 * Initialize the childs stack frame.
684 next->c = g->children;
685 next->result = entry->result;
689 if (!modcall_recurse(request, component, depth + 1, next, true)) {
694 * We've been asked to unwind to the
695 * enclosing "foreach". We're here, so
696 * we can stop unwinding.
698 if (next->unwind == MOD_BREAK) {
704 * Unwind all the way.
706 if (next->unwind == MOD_RETURN) {
707 entry->unwind = MOD_RETURN;
710 } /* loop over VPs */
713 * Free the copied vps and the request data
714 * If we don't remove the request data, something could call
715 * the xlat outside of a foreach loop and trigger a segv.
717 fr_pair_list_free(&vps);
718 request_data_get(request, (void *)radius_get_vp, foreach_depth);
720 rad_assert(next != NULL);
721 result = next->result;
722 priority = next->priority;
724 goto calculate_result;
728 * Break out of a "foreach" loop, or return from a nested
731 if ((c->type == MOD_BREAK) || (c->type == MOD_RETURN)) {
735 RDEBUG2("%s", unlang_keyword[c->type]);
737 for (i = 8; i >= 0; i--) {
738 copy_p = request_data_get(request, (void *)radius_get_vp, i);
740 if (c->type == MOD_BREAK) {
741 RDEBUG2("# break Foreach-Variable-%d", i);
748 * Leave result / priority on the stack, and stop processing the section.
750 entry->unwind = c->type;
754 #endif /* WITH_UNLANG */
757 * Child is a group that has children of it's own.
759 if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
761 || (c->type == MOD_CASE)
769 g = mod_callabletogroup(c);
772 * This should really have been caught in the
773 * compiler, and the node never generated. But
774 * doing that requires changing it's API so that
775 * it returns a flag instead of the compiled
779 if (c->type == MOD_CASE) {
780 result = RLM_MODULE_NOOP;
781 goto calculate_result;
784 RDEBUG2("%s { ... } # empty sub-section is ignored", c->name);
789 modcall_child(request, component,
790 depth + 1, entry, g->children,
793 goto calculate_result;
797 if (c->type == MOD_SWITCH) {
798 modcallable *this, *found, *null_case;
807 g = mod_callabletogroup(c);
809 memset(&cond, 0, sizeof(cond));
810 memset(&map, 0, sizeof(map));
812 cond.type = COND_TYPE_MAP;
813 cond.data.map = ↦
815 map.op = T_OP_CMP_EQ;
816 map.ci = cf_section_to_item(g->cs);
818 rad_assert(g->vpt != NULL);
820 null_case = found = NULL;
824 * The attribute doesn't exist. We can skip
825 * directly to the default 'case' statement.
827 if ((g->vpt->type == TMPL_TYPE_ATTR) && (tmpl_find_vp(NULL, request, g->vpt) < 0)) {
829 for (this = g->children; this; this = this->next) {
830 rad_assert(this->type == MOD_CASE);
832 h = mod_callabletogroup(this);
833 if (h->vpt) continue;
843 * Expand the template if necessary, so that it
844 * is evaluated once instead of for each 'case'
847 if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
848 (g->vpt->type == TMPL_TYPE_XLAT) ||
849 (g->vpt->type == TMPL_TYPE_EXEC)) {
853 len = tmpl_aexpand(request, &p, request, g->vpt, NULL, NULL);
854 if (len < 0) goto find_null_case;
856 tmpl_init(&vpt, TMPL_TYPE_LITERAL, data.strvalue, len);
860 * Find either the exact matching name, or the
861 * "case {...}" statement.
863 for (this = g->children; this; this = this->next) {
864 rad_assert(this->type == MOD_CASE);
866 h = mod_callabletogroup(this);
869 * Remember the default case
872 if (!null_case) null_case = this;
877 * If we're switching over an attribute
878 * AND we haven't pre-parsed the data for
879 * the case statement, then cast the data
880 * to the type of the attribute.
882 if ((g->vpt->type == TMPL_TYPE_ATTR) &&
883 (h->vpt->type != TMPL_TYPE_DATA)) {
886 cond.cast = g->vpt->tmpl_da;
889 * Remove unnecessary casting.
891 if ((h->vpt->type == TMPL_TYPE_ATTR) &&
892 (g->vpt->tmpl_da->type == h->vpt->tmpl_da->type)) {
897 * Use the pre-expanded string.
899 } else if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
900 (g->vpt->type == TMPL_TYPE_XLAT) ||
901 (g->vpt->type == TMPL_TYPE_EXEC)) {
907 * Else evaluate the 'switch' statement.
915 if (radius_evaluate_map(request, RLM_MODULE_UNKNOWN, 0,
922 if (!found) found = null_case;
925 talloc_free(data.ptr);
926 modcall_child(request, component, depth + 1, entry, found, &result, true);
928 goto calculate_result;
932 if ((c->type == MOD_LOAD_BALANCE) ||
933 (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
935 modcallable *this, *found;
940 g = mod_callabletogroup(c);
942 rad_assert(g->children != NULL);
945 * Choose a child at random.
947 for (this = g->children; this; this = this->next) {
950 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
955 if (c->type == MOD_LOAD_BALANCE) {
956 modcall_child(request, component,
957 depth + 1, entry, found,
964 modcall_child(request, component,
965 depth + 1, entry, this,
967 if (this->actions[result] == MOD_ACTION_RETURN) {
973 if (!this) this = g->children;
974 } while (this != found);
977 goto calculate_result;
978 } /* MOD_LOAD_BALANCE */
981 * Reference another virtual server.
983 * This should really be deleted, and replaced with a
984 * more abstracted / functional version.
986 if (c->type == MOD_REFERENCE) {
987 modref *mr = mod_callabletoref(c);
988 char const *server = request->server;
990 if (server == mr->ref_name) {
991 RWDEBUG("Suppressing recursive call to server %s", server);
995 request->server = mr->ref_name;
996 RDEBUG("server %s { # nested call", mr->ref_name);
997 result = indexed_modcall(component, 0, request);
998 RDEBUG("} # server %s with nested call", mr->ref_name);
999 request->server = server;
1000 goto calculate_result;
1001 } /* MOD_REFERENCE */
1004 * xlat a string without doing anything else
1006 * This should really be deleted, and replaced with a
1007 * more abstracted / functional version.
1009 if (c->type == MOD_XLAT) {
1010 modxlat *mx = mod_callabletoxlat(c);
1014 radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
1016 RDEBUG("`%s`", mx->xlat_name);
1017 radius_exec_program(request, NULL, 0, NULL, request, mx->xlat_name, request->packet->vps,
1018 false, true, EXEC_TIMEOUT);
1025 * Add new module types here.
1030 RDEBUG("(%s, %d) ? (%s, %d)",
1031 fr_int2str(mod_rcode_table, result, "<invalid>"),
1033 fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
1038 rad_assert(result != RLM_MODULE_UNKNOWN);
1041 * The child's action says return. Do so.
1043 if ((c->actions[result] == MOD_ACTION_RETURN) &&
1045 entry->result = result;
1050 * If "reject", break out of the loop and return
1053 if (c->actions[result] == MOD_ACTION_REJECT) {
1054 entry->result = RLM_MODULE_REJECT;
1059 * The array holds a default priority for this return
1060 * code. Grab it in preference to any unset priority.
1063 priority = c->actions[result];
1067 * We're higher than any previous priority, remember this
1068 * return code and priority.
1070 if (priority > entry->priority) {
1071 entry->result = result;
1072 entry->priority = priority;
1077 * If we're processing a "case" statement, we return once
1078 * it's done, rather than going to the next "case" statement.
1080 if (c->type == MOD_CASE) goto finish;
1084 * If we've been told to stop processing
1087 if (entry->unwind == MOD_BREAK) {
1088 RDEBUG2("# unwind to enclosing foreach");
1092 if (entry->unwind == MOD_RETURN) {
1097 if (do_next_sibling) {
1098 entry->c = entry->c->next;
1100 if (entry->c) goto redo;
1112 /** Call a module, iteratively, with a local stack, rather than recursively
1114 * What did Paul Graham say about Lisp...?
1116 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1118 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1121 memset(stack, 0, sizeof(stack));
1124 * Set up the initial stack frame.
1127 stack[0].result = default_component_results[component];
1128 stack[0].priority = 0;
1129 stack[0].unwind = 0;
1132 * Call the main handler.
1134 if (!modcall_recurse(request, component, 0, &stack[0], true)) {
1135 return RLM_MODULE_FAIL;
1139 * Return the result.
1141 return stack[0].result;
1146 static char const *action2str(int action)
1148 static char buf[32];
1149 if(action==MOD_ACTION_RETURN)
1151 if(action==MOD_ACTION_REJECT)
1153 snprintf(buf, sizeof buf, "%d", action);
1157 /* If you suspect a bug in the parser, you'll want to use these dump
1158 * functions. dump_tree should reproduce a whole tree exactly as it was found
1159 * in radiusd.conf, but in long form (all actions explicitly defined) */
1160 static void dump_mc(modcallable *c, int indent)
1164 if(c->type==MOD_SINGLE) {
1165 modsingle *single = mod_callabletosingle(c);
1166 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1167 single->modinst->name);
1168 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1169 modgroup *g = mod_callabletogroup(c);
1171 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1172 unlang_keyword[c->type]);
1173 for(p = g->children;p;p = p->next)
1174 dump_mc(p, indent+1);
1175 } /* else ignore it for now */
1177 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1178 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1179 fr_int2str(mod_rcode_table, i, "<invalid>"),
1180 action2str(c->actions[i]));
1183 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1186 static void dump_tree(rlm_components_t comp, modcallable *c)
1188 DEBUG("[%s]", comp2str[comp]);
1192 #define dump_tree(a, b)
1195 /* These are the default actions. For each component, the group{} block
1196 * behaves like the code from the old module_*() function. redundant{}
1197 * are based on my guesses of what they will be used for. --Pac. */
1199 defaultactions[MOD_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1205 MOD_ACTION_RETURN, /* reject */
1207 MOD_ACTION_RETURN, /* ok */
1208 MOD_ACTION_RETURN, /* handled */
1210 MOD_ACTION_RETURN, /* userlock */
1211 MOD_ACTION_RETURN, /* notfound */
1217 MOD_ACTION_RETURN, /* reject */
1219 MOD_ACTION_RETURN, /* ok */
1220 MOD_ACTION_RETURN, /* handled */
1221 MOD_ACTION_RETURN, /* invalid */
1222 MOD_ACTION_RETURN, /* userlock */
1223 MOD_ACTION_RETURN, /* notfound */
1224 MOD_ACTION_RETURN, /* noop */
1225 MOD_ACTION_RETURN /* updated */
1232 MOD_ACTION_RETURN, /* reject */
1233 MOD_ACTION_RETURN, /* fail */
1235 MOD_ACTION_RETURN, /* handled */
1236 MOD_ACTION_RETURN, /* invalid */
1237 MOD_ACTION_RETURN, /* userlock */
1244 MOD_ACTION_RETURN, /* reject */
1246 MOD_ACTION_RETURN, /* ok */
1247 MOD_ACTION_RETURN, /* handled */
1248 MOD_ACTION_RETURN, /* invalid */
1249 MOD_ACTION_RETURN, /* userlock */
1250 MOD_ACTION_RETURN, /* notfound */
1251 MOD_ACTION_RETURN, /* noop */
1252 MOD_ACTION_RETURN /* updated */
1259 MOD_ACTION_RETURN, /* reject */
1260 MOD_ACTION_RETURN, /* fail */
1262 MOD_ACTION_RETURN, /* handled */
1263 MOD_ACTION_RETURN, /* invalid */
1264 MOD_ACTION_RETURN, /* userlock */
1265 MOD_ACTION_RETURN, /* notfound */
1271 MOD_ACTION_RETURN, /* reject */
1273 MOD_ACTION_RETURN, /* ok */
1274 MOD_ACTION_RETURN, /* handled */
1275 MOD_ACTION_RETURN, /* invalid */
1276 MOD_ACTION_RETURN, /* userlock */
1277 MOD_ACTION_RETURN, /* notfound */
1278 MOD_ACTION_RETURN, /* noop */
1279 MOD_ACTION_RETURN /* updated */
1286 MOD_ACTION_RETURN, /* reject */
1287 MOD_ACTION_RETURN, /* fail */
1289 MOD_ACTION_RETURN, /* handled */
1290 MOD_ACTION_RETURN, /* invalid */
1291 MOD_ACTION_RETURN, /* userlock */
1292 MOD_ACTION_RETURN, /* notfound */
1300 MOD_ACTION_RETURN, /* ok */
1301 MOD_ACTION_RETURN, /* handled */
1313 MOD_ACTION_RETURN, /* reject */
1315 MOD_ACTION_RETURN, /* ok */
1316 MOD_ACTION_RETURN, /* handled */
1317 MOD_ACTION_RETURN, /* invalid */
1318 MOD_ACTION_RETURN, /* userlock */
1319 MOD_ACTION_RETURN, /* notfound */
1320 MOD_ACTION_RETURN, /* noop */
1321 MOD_ACTION_RETURN /* updated */
1325 MOD_ACTION_RETURN, /* reject */
1327 MOD_ACTION_RETURN, /* ok */
1328 MOD_ACTION_RETURN, /* handled */
1329 MOD_ACTION_RETURN, /* invalid */
1330 MOD_ACTION_RETURN, /* userlock */
1331 MOD_ACTION_RETURN, /* notfound */
1332 MOD_ACTION_RETURN, /* noop */
1333 MOD_ACTION_RETURN /* updated */
1340 MOD_ACTION_RETURN, /* reject */
1341 MOD_ACTION_RETURN, /* fail */
1343 MOD_ACTION_RETURN, /* handled */
1344 MOD_ACTION_RETURN, /* invalid */
1345 MOD_ACTION_RETURN, /* userlock */
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 */
1367 MOD_ACTION_RETURN, /* reject */
1368 MOD_ACTION_RETURN, /* fail */
1370 MOD_ACTION_RETURN, /* handled */
1371 MOD_ACTION_RETURN, /* invalid */
1372 MOD_ACTION_RETURN, /* userlock */
1379 MOD_ACTION_RETURN, /* reject */
1381 MOD_ACTION_RETURN, /* ok */
1382 MOD_ACTION_RETURN, /* handled */
1383 MOD_ACTION_RETURN, /* invalid */
1384 MOD_ACTION_RETURN, /* userlock */
1385 MOD_ACTION_RETURN, /* notfound */
1386 MOD_ACTION_RETURN, /* noop */
1387 MOD_ACTION_RETURN /* updated */
1394 MOD_ACTION_RETURN, /* reject */
1395 MOD_ACTION_RETURN, /* fail */
1397 MOD_ACTION_RETURN, /* handled */
1398 MOD_ACTION_RETURN, /* invalid */
1399 MOD_ACTION_RETURN, /* userlock */
1406 MOD_ACTION_RETURN, /* reject */
1408 MOD_ACTION_RETURN, /* ok */
1409 MOD_ACTION_RETURN, /* handled */
1410 MOD_ACTION_RETURN, /* invalid */
1411 MOD_ACTION_RETURN, /* userlock */
1412 MOD_ACTION_RETURN, /* notfound */
1413 MOD_ACTION_RETURN, /* noop */
1414 MOD_ACTION_RETURN /* updated */
1423 MOD_ACTION_RETURN, /* reject */
1424 MOD_ACTION_RETURN, /* fail */
1426 MOD_ACTION_RETURN, /* handled */
1427 MOD_ACTION_RETURN, /* invalid */
1428 MOD_ACTION_RETURN, /* userlock */
1435 MOD_ACTION_RETURN, /* reject */
1437 MOD_ACTION_RETURN, /* ok */
1438 MOD_ACTION_RETURN, /* handled */
1439 MOD_ACTION_RETURN, /* invalid */
1440 MOD_ACTION_RETURN, /* userlock */
1441 MOD_ACTION_RETURN, /* notfound */
1442 MOD_ACTION_RETURN, /* noop */
1443 MOD_ACTION_RETURN /* updated */
1450 MOD_ACTION_RETURN, /* reject */
1451 MOD_ACTION_RETURN, /* fail */
1453 MOD_ACTION_RETURN, /* handled */
1454 MOD_ACTION_RETURN, /* invalid */
1455 MOD_ACTION_RETURN, /* userlock */
1462 MOD_ACTION_RETURN, /* reject */
1464 MOD_ACTION_RETURN, /* ok */
1465 MOD_ACTION_RETURN, /* handled */
1466 MOD_ACTION_RETURN, /* invalid */
1467 MOD_ACTION_RETURN, /* userlock */
1468 MOD_ACTION_RETURN, /* notfound */
1469 MOD_ACTION_RETURN, /* noop */
1470 MOD_ACTION_RETURN /* updated */
1476 static const int authtype_actions[GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1480 MOD_ACTION_RETURN, /* reject */
1481 MOD_ACTION_RETURN, /* fail */
1483 MOD_ACTION_RETURN, /* handled */
1484 MOD_ACTION_RETURN, /* invalid */
1485 MOD_ACTION_RETURN, /* userlock */
1492 MOD_ACTION_RETURN, /* reject */
1494 MOD_ACTION_RETURN, /* ok */
1495 MOD_ACTION_RETURN, /* handled */
1496 MOD_ACTION_RETURN, /* invalid */
1497 MOD_ACTION_RETURN, /* userlock */
1498 MOD_ACTION_RETURN, /* notfound */
1499 MOD_ACTION_RETURN, /* noop */
1500 MOD_ACTION_RETURN /* updated */
1504 /** Validate and fixup a map that's part of an update section.
1506 * @param map to validate.
1507 * @param ctx data to pass to fixup function (currently unused).
1508 * @return 0 if valid else -1.
1510 int modcall_fixup_update(vp_map_t *map, UNUSED void *ctx)
1512 CONF_PAIR *cp = cf_item_to_pair(map->ci);
1515 * Anal-retentive checks.
1517 if (DEBUG_ENABLED3) {
1518 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->name[0] != '&')) {
1519 WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
1520 cf_pair_filename(cp), cf_pair_lineno(cp),
1521 map->lhs->name, fr_int2str(fr_tokens, map->op, "<INVALID>"));
1524 if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->name[0] != '&')) {
1525 WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
1526 cf_pair_filename(cp), cf_pair_lineno(cp),
1527 fr_int2str(fr_tokens, map->op, "<INVALID>"), map->rhs->name);
1532 * Values used by unary operators should be literal ANY
1534 * We then free the template and alloc a NULL one instead.
1536 if (map->op == T_OP_CMP_FALSE) {
1537 if ((map->rhs->type != TMPL_TYPE_LITERAL) || (strcmp(map->rhs->name, "ANY") != 0)) {
1538 WARN("%s[%d] Wildcard deletion MUST use '!* ANY'",
1539 cf_pair_filename(cp), cf_pair_lineno(cp));
1542 TALLOC_FREE(map->rhs);
1544 map->rhs = tmpl_alloc(map, TMPL_TYPE_NULL, NULL, 0);
1548 * Lots of sanity checks for insane people...
1552 * What exactly where you expecting to happen here?
1554 if ((map->lhs->type == TMPL_TYPE_ATTR) &&
1555 (map->rhs->type == TMPL_TYPE_LIST)) {
1556 cf_log_err(map->ci, "Can't copy list into an attribute");
1561 * Depending on the attribute type, some operators are disallowed.
1563 if ((map->lhs->type == TMPL_TYPE_ATTR) && (!fr_assignment_op[map->op] && !fr_equality_op[map->op])) {
1564 cf_log_err(map->ci, "Invalid operator \"%s\" in update section. "
1565 "Only assignment or filter operators are allowed",
1566 fr_int2str(fr_tokens, map->op, "<INVALID>"));
1570 if (map->lhs->type == TMPL_TYPE_LIST) {
1572 * Can't copy an xlat expansion or literal into a list,
1573 * we don't know what type of attribute we'd need
1576 * The only exception is where were using a unary
1579 if (map->op != T_OP_CMP_FALSE) switch (map->rhs->type) {
1580 case TMPL_TYPE_XLAT:
1581 case TMPL_TYPE_LITERAL:
1582 cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
1590 * Only += and :=, and !* operators are supported
1594 case T_OP_CMP_FALSE:
1598 if ((map->rhs->type != TMPL_TYPE_LIST) &&
1599 (map->rhs->type != TMPL_TYPE_EXEC)) {
1600 cf_log_err(map->ci, "Invalid source for list assignment '%s += ...'", map->lhs->name);
1606 if (map->rhs->type == TMPL_TYPE_EXEC) {
1607 WARN("%s[%d]: Please change ':=' to '=' for list assignment",
1608 cf_pair_filename(cp), cf_pair_lineno(cp));
1611 if (map->rhs->type != TMPL_TYPE_LIST) {
1612 cf_log_err(map->ci, "Invalid source for list assignment '%s := ...'", map->lhs->name);
1618 if (map->rhs->type != TMPL_TYPE_EXEC) {
1619 cf_log_err(map->ci, "Invalid source for list assignment '%s = ...'", map->lhs->name);
1625 cf_log_err(map->ci, "Operator \"%s\" not allowed for list assignment",
1626 fr_int2str(fr_tokens, map->op, "<INVALID>"));
1632 * If the map has a unary operator there's no further
1633 * processing we need to, as RHS is unused.
1635 if (map->op == T_OP_CMP_FALSE) return 0;
1638 * If LHS is an attribute, and RHS is a literal, we can
1639 * preparse the information into a TMPL_TYPE_DATA.
1641 * Unless it's a unary operator in which case we
1644 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->rhs->type == TMPL_TYPE_LITERAL)) {
1646 * It's a literal string, just copy it.
1647 * Don't escape anything.
1649 if (!cf_new_escape &&
1650 (map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
1651 (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
1652 tmpl_cast_in_place_str(map->rhs);
1656 * RHS is hex, try to parse it as
1657 * type-specific data.
1659 if (map->lhs->auto_converted &&
1660 (map->rhs->name[0] == '0') && (map->rhs->name[1] == 'x') &&
1661 (map->rhs->len > 2) && ((map->rhs->len & 0x01) == 0)) {
1662 vp_tmpl_t *vpt = map->rhs;
1665 if (!map_cast_from_hex(map, T_BARE_WORD, vpt->name)) {
1667 cf_log_err(map->ci, "%s", fr_strerror());
1672 } else if (tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da) < 0) {
1673 cf_log_err(map->ci, "%s", fr_strerror());
1678 * Fixup LHS da if it doesn't match the type
1681 if (map->lhs->tmpl_da->type != map->rhs->tmpl_data_type) {
1682 DICT_ATTR const *da;
1684 da = dict_attrbytype(map->lhs->tmpl_da->attr, map->lhs->tmpl_da->vendor,
1685 map->rhs->tmpl_data_type);
1687 fr_strerror_printf("Cannot find %s variant of attribute \"%s\"",
1688 fr_int2str(dict_attr_types, map->rhs->tmpl_data_type,
1689 "<INVALID>"), map->lhs->tmpl_da->name);
1692 map->lhs->tmpl_da = da;
1695 } /* else we can't precompile the data */
1702 static modcallable *do_compile_modupdate(modcallable *parent, rlm_components_t component,
1703 CONF_SECTION *cs, char const *name2)
1707 modcallable *csingle;
1712 * This looks at cs->name2 to determine which list to update
1714 rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, modcall_fixup_update, NULL, 128);
1715 if (rcode < 0) return NULL; /* message already printed */
1717 cf_log_err_cs(cs, "'update' sections cannot be empty");
1721 g = talloc_zero(parent, modgroup);
1722 csingle = mod_grouptocallable(g);
1724 csingle->parent = parent;
1725 csingle->next = NULL;
1728 csingle->name = name2;
1732 csingle->type = MOD_UPDATE;
1733 csingle->method = component;
1735 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1736 sizeof(csingle->actions));
1738 g->grouptype = GROUPTYPE_SIMPLE;
1741 g->map = talloc_steal(g, head);
1747 static modcallable *do_compile_modswitch (modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1752 bool had_seen_default = false;
1753 modcallable *csingle;
1758 name2 = cf_section_name2(cs);
1760 cf_log_err_cs(cs, "You must specify a variable to switch over for 'switch'");
1764 if (!cf_item_find_next(cs, NULL)) {
1765 cf_log_err_cs(cs, "'switch' statements cannot be empty");
1770 * Create the template. If we fail, AND it's a bare word
1771 * with &Foo-Bar, it MAY be an attribute defined by a
1772 * module. Allow it for now. The pass2 checks below
1775 type = cf_section_name2_type(cs);
1776 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
1777 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1778 char *spaces, *text;
1780 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1782 cf_log_err_cs(cs, "Syntax error");
1783 cf_log_err_cs(cs, "%s", name2);
1784 cf_log_err_cs(cs, "%s^ %s", spaces, text);
1786 talloc_free(spaces);
1793 * Otherwise a NULL vpt may refer to an attribute defined
1794 * by a module. That is checked in pass 2.
1797 if (vpt->type == TMPL_TYPE_LIST) {
1798 cf_log_err_cs(cs, "Syntax error: Cannot switch over list '%s'", name2);
1804 * Walk through the children of the switch section,
1805 * ensuring that they're all 'case' statements
1807 for (ci = cf_item_find_next(cs, NULL);
1809 ci = cf_item_find_next(cs, ci)) {
1810 CONF_SECTION *subcs;
1813 if (!cf_item_is_section(ci)) {
1814 if (!cf_item_is_pair(ci)) continue;
1816 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1821 subcs = cf_item_to_section(ci); /* can't return NULL */
1822 name1 = cf_section_name1(subcs);
1824 if (strcmp(name1, "case") != 0) {
1825 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1830 name2 = cf_section_name2(subcs);
1832 if (!had_seen_default) {
1833 had_seen_default = true;
1837 cf_log_err(ci, "Cannot have two 'default' case statements");
1843 csingle = do_compile_modgroup(parent, component, cs,
1852 g = mod_callabletogroup(csingle);
1853 g->vpt = talloc_steal(g, vpt);
1858 static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1862 modcallable *csingle;
1866 if (!parent || (parent->type != MOD_SWITCH)) {
1867 cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
1872 * case THING means "match THING"
1873 * case means "match anything"
1875 name2 = cf_section_name2(cs);
1880 type = cf_section_name2_type(cs);
1882 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
1883 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1884 char *spaces, *text;
1886 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1888 cf_log_err_cs(cs, "Syntax error");
1889 cf_log_err_cs(cs, "%s", name2);
1890 cf_log_err_cs(cs, "%s^ %s", spaces, text);
1892 talloc_free(spaces);
1898 if (vpt->type == TMPL_TYPE_LIST) {
1899 cf_log_err_cs(cs, "Syntax error: Cannot match list '%s'", name2);
1904 * Otherwise a NULL vpt may refer to an attribute defined
1905 * by a module. That is checked in pass 2.
1912 csingle = do_compile_modgroup(parent, component, cs,
1922 * The interpretor expects this to be NULL for the
1923 * default case. do_compile_modgroup sets it to name2,
1924 * unless name2 is NULL, in which case it sets it to name1.
1926 csingle->name = name2;
1928 g = mod_callabletogroup(csingle);
1929 g->vpt = talloc_steal(g, vpt);
1932 * Set all of it's codes to return, so that
1933 * when we pick a 'case' statement, we don't
1934 * fall through to processing the next one.
1936 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1937 csingle->actions[i] = MOD_ACTION_RETURN;
1943 static modcallable *do_compile_modforeach(modcallable *parent,
1944 rlm_components_t component, CONF_SECTION *cs)
1948 modcallable *csingle;
1953 name2 = cf_section_name2(cs);
1956 "You must specify an attribute to loop over in 'foreach'");
1960 if (!cf_item_find_next(cs, NULL)) {
1961 cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
1966 * Create the template. If we fail, AND it's a bare word
1967 * with &Foo-Bar, it MAY be an attribute defined by a
1968 * module. Allow it for now. The pass2 checks below
1971 type = cf_section_name2_type(cs);
1972 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
1973 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1974 char *spaces, *text;
1976 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1978 cf_log_err_cs(cs, "Syntax error");
1979 cf_log_err_cs(cs, "%s", name2);
1980 cf_log_err_cs(cs, "%s^ %s", spaces, text);
1982 talloc_free(spaces);
1989 * If we don't have a negative return code, we must have a vpt
1990 * (mostly to quiet coverity).
1994 if ((vpt->type != TMPL_TYPE_ATTR) && (vpt->type != TMPL_TYPE_LIST)) {
1995 cf_log_err_cs(cs, "MUST use attribute or list reference in 'foreach'");
2000 * Fix up the template to iterate over all instances of
2001 * the attribute. In a perfect consistent world, users would do
2002 * foreach &attr[*], but that's taking the consistency thing a bit far.
2004 vpt->tmpl_num = NUM_ALL;
2006 csingle = do_compile_modgroup(parent, component, cs,
2007 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2015 g = mod_callabletogroup(csingle);
2021 static modcallable *do_compile_modbreak(modcallable *parent,
2022 rlm_components_t component, CONF_ITEM const *ci)
2024 CONF_SECTION const *cs = NULL;
2026 for (cs = cf_item_parent(ci);
2028 cs = cf_item_parent(cf_section_to_item(cs))) {
2029 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
2035 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
2039 return do_compile_modgroup(parent, component, NULL,
2040 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2045 static modcallable *do_compile_modserver(modcallable *parent,
2046 rlm_components_t component, CONF_ITEM *ci,
2051 modcallable *csingle;
2052 CONF_SECTION *subcs;
2055 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
2057 cf_log_err(ci, "Server %s has no %s section",
2058 server, comp2str[component]);
2062 mr = talloc_zero(parent, modref);
2064 csingle = mod_reftocallable(mr);
2065 csingle->parent = parent;
2066 csingle->next = NULL;
2067 csingle->name = name;
2068 csingle->type = MOD_REFERENCE;
2069 csingle->method = component;
2071 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2072 sizeof(csingle->actions));
2074 mr->ref_name = strdup(server);
2080 static modcallable *do_compile_modxlat(modcallable *parent,
2081 rlm_components_t component, char const *fmt)
2083 modcallable *csingle;
2086 mx = talloc_zero(parent, modxlat);
2088 csingle = mod_xlattocallable(mx);
2089 csingle->parent = parent;
2090 csingle->next = NULL;
2091 csingle->name = "expand";
2092 csingle->type = MOD_XLAT;
2093 csingle->method = component;
2095 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2096 sizeof(csingle->actions));
2098 mx->xlat_name = strdup(fmt);
2099 if (fmt[0] != '%') {
2103 strcpy(mx->xlat_name, fmt + 1);
2104 p = strrchr(mx->xlat_name, '`');
2112 * redundant, etc. can refer to modules or groups, but not much else.
2114 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
2118 for (ci=cf_item_find_next(cs, NULL);
2120 ci=cf_item_find_next(cs, ci)) {
2122 * If we're a redundant, etc. group, then the
2123 * intention is to call modules, rather than
2124 * processing logic. These checks aren't
2125 * *strictly* necessary, but they keep the users
2126 * from doing crazy things.
2128 if (cf_item_is_section(ci)) {
2129 CONF_SECTION *subcs = cf_item_to_section(ci);
2130 char const *name1 = cf_section_name1(subcs);
2132 if ((strcmp(name1, "if") == 0) ||
2133 (strcmp(name1, "else") == 0) ||
2134 (strcmp(name1, "elsif") == 0) ||
2135 (strcmp(name1, "update") == 0) ||
2136 (strcmp(name1, "switch") == 0) ||
2137 (strcmp(name1, "case") == 0)) {
2138 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
2145 if (cf_item_is_pair(ci)) {
2146 CONF_PAIR *cp = cf_item_to_pair(ci);
2147 if (cf_pair_value(cp) != NULL) {
2149 "Entry with no value is invalid");
2158 /** Load a named module from "instantiate" or "policy".
2160 * If it's "foo.method", look for "foo", and return "method" as the method
2161 * we wish to use, instead of the input component.
2163 * @param[out] pcomponent Where to write the method we found, if any. If no method is specified
2164 * will be set to MOD_COUNT.
2165 * @param[in] real_name Complete name string e.g. foo.authorize.
2166 * @param[in] virtual_name Virtual module name e.g. foo.
2167 * @param[in] method_name Method override (may be NULL) or the method name e.g. authorize.
2168 * @return the CONF_SECTION specifying the virtual module.
2170 static CONF_SECTION *virtual_module_find_cs(rlm_components_t *pcomponent,
2171 char const *real_name, char const *virtual_name, char const *method_name)
2173 CONF_SECTION *cs, *subcs;
2174 rlm_components_t method = *pcomponent;
2178 * Turn the method name into a method enum.
2183 for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
2184 if (strcmp(comp2str[i], method_name) == 0) break;
2187 if (i != MOD_COUNT) {
2191 virtual_name = real_name;
2196 * Look for "foo" in the "instantiate" section. If we
2197 * find it, AND there's no method name, we've found the
2200 * Return it to the caller, with the updated method.
2202 cs = cf_section_find("instantiate");
2205 * Found "foo". Load it as "foo", or "foo.method".
2207 subcs = cf_section_sub_find_name2(cs, NULL, virtual_name);
2209 *pcomponent = method;
2215 * Look for it in "policy".
2217 * If there's no policy section, we can't do anything else.
2219 cs = cf_section_find("policy");
2220 if (!cs) return NULL;
2223 * "foo.authorize" means "load policy "foo" as method "authorize".
2225 * And bail out if there's no policy "foo".
2228 subcs = cf_section_sub_find_name2(cs, NULL, virtual_name);
2229 if (subcs) *pcomponent = method;
2235 * "foo" means "look for foo.component" first, to allow
2236 * method overrides. If that's not found, just look for
2240 snprintf(buffer, sizeof(buffer), "%s.%s",
2241 virtual_name, comp2str[method]);
2242 subcs = cf_section_sub_find_name2(cs, NULL, buffer);
2243 if (subcs) return subcs;
2245 return cf_section_sub_find_name2(cs, NULL, virtual_name);
2250 * Compile one entry of a module call.
2252 static modcallable *do_compile_modsingle(modcallable *parent,
2253 rlm_components_t component, CONF_ITEM *ci,
2255 char const **modname)
2257 char const *modrefname, *p;
2259 modcallable *csingle;
2260 module_instance_t *this;
2261 CONF_SECTION *cs, *subcs, *modules;
2263 char const *realname;
2264 rlm_components_t method = component;
2266 if (cf_item_is_section(ci)) {
2269 cs = cf_item_to_section(ci);
2270 modrefname = cf_section_name1(cs);
2271 name2 = cf_section_name2(cs);
2272 if (!name2) name2 = "";
2275 * group{}, redundant{}, or append{} may appear
2276 * where a single module instance was expected.
2277 * In that case, we hand it off to
2280 if (strcmp(modrefname, "group") == 0) {
2282 return do_compile_modgroup(parent, component, cs,
2284 grouptype, MOD_GROUP);
2286 } else if (strcmp(modrefname, "redundant") == 0) {
2289 if (!all_children_are_modules(cs, modrefname)) {
2293 return do_compile_modgroup(parent, component, cs,
2294 GROUPTYPE_REDUNDANT,
2295 grouptype, MOD_GROUP);
2297 } else if (strcmp(modrefname, "load-balance") == 0) {
2300 if (!all_children_are_modules(cs, modrefname)) {
2304 return do_compile_modgroup(parent, component, cs,
2306 grouptype, MOD_LOAD_BALANCE);
2308 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
2311 if (!all_children_are_modules(cs, modrefname)) {
2315 return do_compile_modgroup(parent, component, cs,
2316 GROUPTYPE_REDUNDANT,
2317 grouptype, MOD_REDUNDANT_LOAD_BALANCE);
2320 } else if (strcmp(modrefname, "if") == 0) {
2321 if (!cf_section_name2(cs)) {
2322 cf_log_err(ci, "'if' without condition");
2327 csingle= do_compile_modgroup(parent, component, cs,
2330 if (!csingle) return NULL;
2335 } else if (strcmp(modrefname, "elsif") == 0) {
2337 ((parent->type == MOD_LOAD_BALANCE) ||
2338 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2339 cf_log_err(ci, "'elsif' cannot be used in this section");
2343 if (!cf_section_name2(cs)) {
2344 cf_log_err(ci, "'elsif' without condition");
2349 return do_compile_modgroup(parent, component, cs,
2351 grouptype, MOD_ELSIF);
2353 } else if (strcmp(modrefname, "else") == 0) {
2355 ((parent->type == MOD_LOAD_BALANCE) ||
2356 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2357 cf_log_err(ci, "'else' cannot be used in this section section");
2361 if (cf_section_name2(cs)) {
2362 cf_log_err(ci, "Cannot have conditions on 'else'");
2367 return do_compile_modgroup(parent, component, cs,
2369 grouptype, MOD_ELSE);
2371 } else if (strcmp(modrefname, "update") == 0) {
2374 return do_compile_modupdate(parent, component, cs,
2377 } else if (strcmp(modrefname, "switch") == 0) {
2380 return do_compile_modswitch (parent, component, cs);
2382 } else if (strcmp(modrefname, "case") == 0) {
2385 return do_compile_modcase(parent, component, cs);
2387 } else if (strcmp(modrefname, "foreach") == 0) {
2390 return do_compile_modforeach(parent, component, cs);
2393 } /* else it's something like sql { fail = 1 ...} */
2395 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2399 * Else it's a module reference, with updated return
2403 CONF_PAIR *cp = cf_item_to_pair(ci);
2404 modrefname = cf_pair_attr(cp);
2407 * Actions (ok = 1), etc. are orthogonal to just
2408 * about everything else.
2410 if (cf_pair_value(cp) != NULL) {
2411 cf_log_err(ci, "Entry is not a reference to a module");
2416 * In-place xlat's via %{...}.
2418 * This should really be removed from the server.
2420 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2421 (modrefname[0] == '`')) {
2422 return do_compile_modxlat(parent, component,
2429 * These can't be over-ridden.
2431 if (strcmp(modrefname, "break") == 0) {
2432 if (!cf_item_is_pair(ci)) {
2433 cf_log_err(ci, "Invalid use of 'break' as section name.");
2437 return do_compile_modbreak(parent, component, ci);
2440 if (strcmp(modrefname, "return") == 0) {
2441 if (!cf_item_is_pair(ci)) {
2442 cf_log_err(ci, "Invalid use of 'return' as section name.");
2446 return do_compile_modgroup(parent, component, NULL,
2447 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2453 * Run a virtual server. This is really terrible and
2454 * should be deleted.
2456 if (strncmp(modrefname, "server[", 7) == 0) {
2459 if (!cf_item_is_pair(ci)) {
2460 cf_log_err(ci, "Invalid syntax");
2464 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2465 p = strrchr(buffer, ']');
2466 if (!p || p[1] != '\0' || (p == buffer)) {
2467 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2471 buffer[p - buffer] = '\0';
2473 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2475 cf_log_err(ci, "No such server \"%s\".", buffer);
2480 * Ignore stupid attempts to over-ride the return
2483 return do_compile_modserver(parent, component, ci,
2484 modrefname, cs, buffer);
2488 * We now have a name. It can be one of two forms. A
2489 * bare module name, or a section named for the module,
2490 * with over-rides for the return codes.
2492 * The name can refer to a real module, in the "modules"
2493 * section. In that case, the name will be either the
2494 * first or second name of the sub-section of "modules".
2496 * Or, the name can refer to a policy, in the "policy"
2497 * section. In that case, the name will be first name of
2498 * the sub-section of "policy". Unless it's a "redudant"
2501 * Or, the name can refer to a "module.method", in which
2502 * case we're calling a different method than normal for
2505 * Or, the name can refer to a virtual module, in the
2506 * "instantiate" section. In that case, the name will be
2507 * the first of the sub-section of "instantiate". Unless
2508 * it's a "redudant" block...
2510 * We try these in sequence, from the bottom up. This is
2511 * so that things in "instantiate" and "policy" can
2512 * over-ride calls to real modules.
2519 * instantiate { ... name { ...} ... }
2520 * instantiate { ... name.method { ...} ... }
2521 * policy { ... name { .. } .. }
2522 * policy { ... name.method { .. } .. }
2524 * The only difference between things in "instantiate"
2525 * and "policy" is that "instantiate" will cause modules
2526 * to be instantiated in a particular order.
2529 p = strrchr(modrefname, '.');
2531 subcs = virtual_module_find_cs(&method, modrefname, modrefname, NULL);
2535 strlcpy(buffer, modrefname, sizeof(buffer));
2536 buffer[p - modrefname] = '\0';
2538 subcs = virtual_module_find_cs(&method, modrefname, buffer, buffer + (p - modrefname) + 1);
2542 * Check that we're not creating a loop. We may
2543 * be compiling an "sql" module reference inside
2544 * of an "sql" policy. If so, we allow the
2545 * second "sql" to refer to the module.
2547 for (loop = cf_item_parent(ci);
2549 loop = cf_item_parent(cf_section_to_item(loop))) {
2550 if (loop == subcs) {
2556 * We've found the relevant entry. It MUST be a
2559 * However, it can be a "redundant" block, or just a
2564 * modules.c takes care of ensuring that this is:
2567 * load-balance foo { ...
2568 * redundant foo { ...
2569 * redundant-load-balance foo { ...
2571 * We can just recurs to compile the section as
2572 * if it was found here.
2574 if (cf_section_name2(subcs)) {
2575 csingle = do_compile_modsingle(parent,
2577 cf_section_to_item(subcs),
2586 * So we compile it like it was:
2590 csingle = do_compile_modgroup(parent,
2594 grouptype, MOD_GROUP);
2598 * Return the compiled thing if we can.
2600 if (!csingle) return NULL;
2601 if (cf_item_is_pair(ci)) return csingle;
2604 * Else we have a reference to a policy, and that reference
2605 * over-rides the return codes for the policy!
2607 goto action_override;
2611 * Not a virtual module. It must be a real module.
2613 modules = cf_section_find("modules");
2615 realname = modrefname;
2619 * Try to load the optional module.
2621 if (realname[0] == '-') realname++;
2624 * As of v3, the "modules" section contains
2625 * modules we use. Configuration for other
2626 * modules belongs in raddb/mods-available/,
2627 * which isn't loaded into the "modules" section.
2629 this = module_instantiate_method(modules, realname, &method);
2630 if (this) goto allocate_csingle;
2633 * We were asked to MAYBE load it and it
2634 * doesn't exist. Return a soft error.
2636 if (realname != modrefname) {
2637 *modname = modrefname;
2643 * Can't de-reference it to anything. Ugh.
2646 cf_log_err(ci, "Failed to find \"%s\" as a module or policy.", modrefname);
2647 cf_log_err(ci, "Please verify that the configuration exists in %s/mods-enabled/%s.", get_radius_dir(), modrefname);
2651 * We know it's all OK, allocate the structures, and fill
2656 * Check if the module in question has the necessary
2659 if (!this->entry->module->methods[method]) {
2660 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2665 single = talloc_zero(parent, modsingle);
2666 single->modinst = this;
2667 *modname = this->entry->module->name;
2669 csingle = mod_singletocallable(single);
2670 csingle->parent = parent;
2671 csingle->next = NULL;
2672 if (!parent || (component != MOD_AUTHENTICATE)) {
2673 memcpy(csingle->actions, defaultactions[component][grouptype],
2674 sizeof csingle->actions);
2675 } else { /* inside Auth-Type has different rules */
2676 memcpy(csingle->actions, authtype_actions[grouptype],
2677 sizeof csingle->actions);
2679 rad_assert(modrefname != NULL);
2680 csingle->name = realname;
2681 csingle->type = MOD_SINGLE;
2682 csingle->method = method;
2686 * Over-ride the default return codes of the module.
2688 if (cf_item_is_section(ci)) {
2691 cs = cf_item_to_section(ci);
2692 for (csi=cf_item_find_next(cs, NULL);
2694 csi=cf_item_find_next(cs, csi)) {
2696 if (cf_item_is_section(csi)) {
2697 cf_log_err(csi, "Subsection of module instance call not allowed");
2698 talloc_free(csingle);
2702 if (!cf_item_is_pair(csi)) continue;
2704 if (!compile_action(csingle, cf_item_to_pair(csi))) {
2705 talloc_free(csingle);
2714 modcallable *compile_modsingle(TALLOC_CTX *ctx,
2715 modcallable **parent,
2716 rlm_components_t component, CONF_ITEM *ci,
2717 char const **modname)
2724 CONF_SECTION *parentcs;
2726 g = talloc_zero(ctx, modgroup);
2727 memset(g, 0, sizeof(*g));
2728 g->grouptype = GROUPTYPE_SIMPLE;
2729 c = mod_grouptocallable(g);
2732 defaultactions[component][GROUPTYPE_SIMPLE],
2733 sizeof(c->actions));
2735 parentcs = cf_item_parent(ci);
2736 c->name = cf_section_name2(parentcs);
2738 c->name = cf_section_name1(parentcs);
2741 c->type = MOD_GROUP;
2742 c->method = component;
2745 *parent = mod_grouptocallable(g);
2748 ret = do_compile_modsingle(*parent, component, ci,
2751 dump_tree(component, ret);
2757 * Internal compile group code.
2759 static modcallable *do_compile_modgroup(modcallable *parent,
2760 rlm_components_t component, CONF_SECTION *cs,
2761 int grouptype, int parentgrouptype, int mod_type)
2768 g = talloc_zero(parent, modgroup);
2769 g->grouptype = grouptype;
2773 c = mod_grouptocallable(g);
2777 memset(c->actions, 0, sizeof(c->actions));
2779 if (!cs) { /* only for "break" and "return" */
2785 * Remember the name for printing, etc.
2787 * FIXME: We may also want to put the names into a
2788 * rbtree, so that groups can reference each other...
2790 c->name = cf_section_name2(cs);
2792 c->name = cf_section_name1(cs);
2793 if ((strcmp(c->name, "group") == 0) ||
2794 (strcmp(c->name, "redundant") == 0)) {
2796 } else if (c->type == MOD_GROUP) {
2797 c->type = MOD_POLICY;
2803 * Do load-time optimizations
2805 if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
2808 rad_assert(parent != NULL);
2810 if (c->type == MOD_IF) {
2811 g->cond = cf_data_find(g->cs, "if");
2812 rad_assert(g->cond != NULL);
2815 if (g->cond->type == COND_TYPE_FALSE) {
2816 INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
2817 unlang_keyword[g->mc.type],
2818 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2822 } else if (c->type == MOD_ELSIF) {
2824 g->cond = cf_data_find(g->cs, "if");
2825 rad_assert(g->cond != NULL);
2827 rad_assert(parent != NULL);
2828 p = mod_callabletogroup(parent);
2830 if (!p->tail) goto elsif_fail;
2833 * We're in the process of compiling the
2834 * section, so the parent's tail is the
2835 * previous "if" statement.
2837 f = mod_callabletogroup(p->tail);
2838 if ((f->mc.type != MOD_IF) &&
2839 (f->mc.type != MOD_ELSIF)) {
2841 cf_log_err_cs(g->cs, "Invalid location for 'elsif'. There is no preceding 'if' statement");
2847 * If we took the previous condition, we
2848 * don't need to take this one.
2850 * We reset our condition to 'true', so
2851 * that subsequent sections can check
2852 * that they don't need to be executed.
2854 if (f->cond->type == COND_TYPE_TRUE) {
2856 INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
2857 unlang_keyword[g->mc.type],
2858 unlang_keyword[f->mc.type],
2859 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2866 rad_assert(c->type == MOD_ELSE);
2868 rad_assert(parent != NULL);
2869 p = mod_callabletogroup(parent);
2871 if (!p->tail) goto else_fail;
2873 f = mod_callabletogroup(p->tail);
2874 if ((f->mc.type != MOD_IF) &&
2875 (f->mc.type != MOD_ELSIF)) {
2877 cf_log_err_cs(g->cs, "Invalid location for 'else'. There is no preceding 'if' statement");
2883 * If we took the previous condition, we
2884 * don't need to take this one.
2886 if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
2890 * Else we need to compile this section
2896 * Loop over the children of this group.
2898 for (ci=cf_item_find_next(cs, NULL);
2900 ci=cf_item_find_next(cs, ci)) {
2903 * Sections are references to other groups, or
2904 * to modules with updated return codes.
2906 if (cf_item_is_section(ci)) {
2907 char const *junk = NULL;
2908 modcallable *single;
2909 CONF_SECTION *subcs = cf_item_to_section(ci);
2911 single = do_compile_modsingle(c, component, ci,
2914 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2915 cf_section_name1(subcs));
2919 add_child(g, single);
2921 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2925 char const *attr, *value;
2926 CONF_PAIR *cp = cf_item_to_pair(ci);
2928 attr = cf_pair_attr(cp);
2929 value = cf_pair_value(cp);
2932 * A CONF_PAIR is either a module
2933 * instance with no actions
2937 modcallable *single;
2938 char const *junk = NULL;
2940 single = do_compile_modsingle(c,
2946 if (cf_item_is_pair(ci) &&
2947 cf_pair_attr(cf_item_to_pair(ci))[0] == '-') {
2952 "Failed to parse \"%s\" entry.",
2957 add_child(g, single);
2960 * Or a module instance with action.
2962 } else if (!compile_action(c, cp)) {
2965 } /* else it worked */
2971 * Set the default actions, if they haven't already been
2974 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2975 if (!c->actions[i]) {
2976 if (!parent || (component != MOD_AUTHENTICATE)) {
2977 c->actions[i] = defaultactions[component][parentgrouptype][i];
2978 } else { /* inside Auth-Type has different rules */
2979 c->actions[i] = authtype_actions[parentgrouptype][i];
2989 if (grouptype != GROUPTYPE_REDUNDANT) break;
2992 case MOD_LOAD_BALANCE:
2993 case MOD_REDUNDANT_LOAD_BALANCE:
2995 cf_log_err_cs(g->cs, "%s sections cannot be empty",
2996 cf_section_name1(g->cs));
3003 * FIXME: If there are no children, return NULL?
3005 return mod_grouptocallable(g);
3008 modcallable *compile_modgroup(modcallable *parent,
3009 rlm_components_t component, CONF_SECTION *cs)
3011 modcallable *ret = do_compile_modgroup(parent, component, cs,
3013 GROUPTYPE_SIMPLE, MOD_GROUP);
3015 if (rad_debug_lvl > 3) {
3016 modcall_debug(ret, 2);
3022 void add_to_modcallable(modcallable *parent, modcallable *this)
3026 rad_assert(this != NULL);
3027 rad_assert(parent != NULL);
3029 g = mod_callabletogroup(parent);
3036 static bool pass2_xlat_compile(CONF_ITEM const *ci, vp_tmpl_t **pvpt, bool convert,
3037 DICT_ATTR const *da)
3047 rad_assert(vpt->type == TMPL_TYPE_XLAT);
3049 fmt = talloc_typed_strdup(vpt, vpt->name);
3050 slen = xlat_tokenize(vpt, fmt, &head, &error);
3053 char *spaces, *text;
3055 fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
3057 cf_log_err(ci, "Failed parsing expanded string:");
3058 cf_log_err(ci, "%s", text);
3059 cf_log_err(ci, "%s^ %s", spaces, error);
3061 talloc_free(spaces);
3067 * Convert %{Attribute-Name} to &Attribute-Name
3072 attr = xlat_to_tmpl_attr(talloc_parent(vpt), head);
3075 * If it's a virtual attribute, leave it
3078 if (attr->tmpl_da->flags.virtual) {
3084 * If the attribute is of incompatible
3085 * type, leave it alone.
3087 if (da && (da->type != attr->tmpl_da->type)) {
3092 if (cf_item_is_pair(ci)) {
3093 CONF_PAIR *cp = cf_item_to_pair(ci);
3095 WARN("%s[%d]: Please change \"%%{%s}\" to &%s",
3096 cf_pair_filename(cp), cf_pair_lineno(cp),
3097 attr->name, attr->name);
3099 CONF_SECTION *cs = cf_item_to_section(ci);
3101 WARN("%s[%d]: Please change \"%%{%s}\" to &%s",
3102 cf_section_filename(cs), cf_section_lineno(cs),
3103 attr->name, attr->name);
3112 * Re-write it to be a pre-parsed XLAT structure.
3114 vpt->type = TMPL_TYPE_XLAT_STRUCT;
3115 vpt->tmpl_xlat = head;
3122 static bool pass2_regex_compile(CONF_ITEM const *ci, vp_tmpl_t *vpt)
3127 rad_assert(vpt->type == TMPL_TYPE_REGEX);
3130 * It's a dynamic expansion. We can't expand the string,
3131 * but we can pre-parse it as an xlat struct. In that
3132 * case, we convert it to a pre-compiled XLAT.
3134 * This is a little more complicated than it needs to be
3135 * because radius_evaluate_map() keys off of the src
3136 * template type, instead of the operators. And, the
3137 * pass2_xlat_compile() function expects to get passed an
3138 * XLAT instead of a REGEX.
3140 if (strchr(vpt->name, '%')) {
3141 vpt->type = TMPL_TYPE_XLAT;
3142 return pass2_xlat_compile(ci, &vpt, false, NULL);
3145 slen = regex_compile(vpt, &preg, vpt->name, vpt->len,
3146 vpt->tmpl_iflag, vpt->tmpl_mflag, true, false);
3148 char *spaces, *text;
3150 fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
3152 cf_log_err(ci, "Invalid regular expression:");
3153 cf_log_err(ci, "%s", text);
3154 cf_log_err(ci, "%s^ %s", spaces, fr_strerror());
3156 talloc_free(spaces);
3162 vpt->type = TMPL_TYPE_REGEX_STRUCT;
3163 vpt->tmpl_preg = preg;
3169 static bool pass2_fixup_undefined(CONF_ITEM const *ci, vp_tmpl_t *vpt)
3171 DICT_ATTR const *da;
3173 rad_assert(vpt->type == TMPL_TYPE_ATTR_UNDEFINED);
3175 da = dict_attrbyname(vpt->tmpl_unknown_name);
3177 cf_log_err(ci, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
3182 vpt->type = TMPL_TYPE_ATTR;
3186 static bool pass2_callback(void *ctx, fr_cond_t *c)
3192 * These don't get optimized.
3194 if ((c->type == COND_TYPE_TRUE) ||
3195 (c->type == COND_TYPE_FALSE)) {
3202 if (c->type == COND_TYPE_CHILD) return pass2_callback(ctx, c->data.child);
3205 * A few simple checks here.
3207 if (c->type == COND_TYPE_EXISTS) {
3208 if (c->data.vpt->type == TMPL_TYPE_XLAT) {
3209 return pass2_xlat_compile(c->ci, &c->data.vpt, true, NULL);
3212 rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
3215 * The existence check might have been &Foo-Bar,
3216 * where Foo-Bar is defined by a module.
3218 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3219 if (!pass2_fixup_undefined(c->ci, c->data.vpt)) return false;
3220 c->pass2_fixup = PASS2_FIXUP_NONE;
3224 * Convert virtual &Attr-Foo to "%{Attr-Foo}"
3227 if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
3228 vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
3229 vpt->type = TMPL_TYPE_XLAT_STRUCT;
3236 * And tons of complicated checks.
3238 rad_assert(c->type == COND_TYPE_MAP);
3240 map = c->data.map; /* shorter */
3245 * Where "foo" is dynamically defined.
3247 if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
3248 if (!dict_valbyname(map->lhs->tmpl_da->attr,
3249 map->lhs->tmpl_da->vendor,
3251 cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
3252 map->lhs->tmpl_da->name,
3258 * These guys can't have a paircompare fixup applied.
3260 c->pass2_fixup = PASS2_FIXUP_NONE;
3264 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3265 if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3266 if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
3269 if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3270 if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
3273 c->pass2_fixup = PASS2_FIXUP_NONE;
3277 * Just in case someone adds a new fixup later.
3279 rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
3280 (c->pass2_fixup == PASS2_PAIRCOMPARE));
3285 if (map->lhs->type == TMPL_TYPE_XLAT) {
3287 * Compile the LHS to an attribute reference only
3288 * if the RHS is a literal.
3290 * @todo v3.1: allow anything anywhere.
3292 if (map->rhs->type != TMPL_TYPE_LITERAL) {
3293 if (!pass2_xlat_compile(map->ci, &map->lhs, false, NULL)) {
3297 if (!pass2_xlat_compile(map->ci, &map->lhs, true, NULL)) {
3302 * Attribute compared to a literal gets
3303 * the literal cast to the data type of
3306 * The code in parser.c did this for
3310 * But now we've just converted "%{Attr}"
3311 * to &Attr, so we've got to do it again.
3313 if ((map->lhs->type == TMPL_TYPE_ATTR) &&
3314 (map->rhs->type == TMPL_TYPE_LITERAL)) {
3316 * RHS is hex, try to parse it as
3317 * type-specific data.
3319 if (map->lhs->auto_converted &&
3320 (map->rhs->name[0] == '0') && (map->rhs->name[1] == 'x') &&
3321 (map->rhs->len > 2) && ((map->rhs->len & 0x01) == 0)) {
3325 if (!map_cast_from_hex(map, T_BARE_WORD, vpt->name)) {
3327 cf_log_err(map->ci, "%s", fr_strerror());
3332 } else if ((map->rhs->len > 0) ||
3333 (map->op != T_OP_CMP_EQ) ||
3334 (map->lhs->tmpl_da->type == PW_TYPE_STRING) ||
3335 (map->lhs->tmpl_da->type == PW_TYPE_OCTETS)) {
3337 if (tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da) < 0) {
3338 cf_log_err(map->ci, "Failed to parse data type %s from string: %s",
3339 fr_int2str(dict_attr_types, map->lhs->tmpl_da->type, "<UNKNOWN>"),
3342 } /* else the cast was successful */
3344 } else { /* RHS is empty, it's just a check for empty / non-empty string */
3345 vpt = talloc_steal(c, map->lhs);
3347 talloc_free(c->data.map);
3350 * "%{Foo}" == '' ---> !Foo
3351 * "%{Foo}" != '' ---> Foo
3353 c->type = COND_TYPE_EXISTS;
3355 c->negate = !c->negate;
3357 WARN("%s[%d]: Please change (\"%%{%s}\" %s '') to %c&%s",
3358 cf_section_filename(cf_item_to_section(c->ci)),
3359 cf_section_lineno(cf_item_to_section(c->ci)),
3360 vpt->name, c->negate ? "==" : "!=",
3361 c->negate ? '!' : ' ', vpt->name);
3364 * No more RHS, so we can't do more optimizations
3372 if (map->rhs->type == TMPL_TYPE_XLAT) {
3374 * Convert the RHS to an attribute reference only
3375 * if the LHS is an attribute reference, AND is
3376 * of the same type as the RHS.
3378 * We can fix this when the code in evaluate.c
3379 * can handle strings on the LHS, and attributes
3380 * on the RHS. For now, the code in parser.c
3383 if (map->lhs->type == TMPL_TYPE_ATTR) {
3384 DICT_ATTR const *da = c->cast;
3386 if (!c->cast) da = map->lhs->tmpl_da;
3388 if (!pass2_xlat_compile(map->ci, &map->rhs, true, da)) {
3393 if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3400 * Convert bare refs to %{Foreach-Variable-N}
3402 if ((map->lhs->type == TMPL_TYPE_LITERAL) &&
3403 (strncmp(map->lhs->name, "Foreach-Variable-", 17) == 0)) {
3407 fmt = talloc_asprintf(map->lhs, "%%{%s}", map->lhs->name);
3408 slen = tmpl_afrom_str(map, &vpt, fmt, talloc_array_length(fmt) - 1,
3409 T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
3411 char *spaces, *text;
3413 fr_canonicalize_error(map->ci, &spaces, &text, slen, fr_strerror());
3415 cf_log_err(map->ci, "Failed converting %s to xlat", map->lhs->name);
3416 cf_log_err(map->ci, "%s", fmt);
3417 cf_log_err(map->ci, "%s^ %s", spaces, text);
3419 talloc_free(spaces);
3425 talloc_free(map->lhs);
3430 if (map->rhs->type == TMPL_TYPE_REGEX) {
3431 if (!pass2_regex_compile(map->ci, map->rhs)) {
3435 rad_assert(map->lhs->type != TMPL_TYPE_REGEX);
3439 * Convert &Packet-Type to "%{Packet-Type}", because
3440 * these attributes don't really exist. The code to
3441 * find an attribute reference doesn't work, but the
3444 vpt = c->data.map->lhs;
3445 if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
3446 if (!c->cast) c->cast = vpt->tmpl_da;
3447 vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
3448 vpt->type = TMPL_TYPE_XLAT_STRUCT;
3452 * Convert RHS to expansions, too.
3454 vpt = c->data.map->rhs;
3455 if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
3456 vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
3457 vpt->type = TMPL_TYPE_XLAT_STRUCT;
3461 * @todo v3.1: do the same thing for the RHS...
3465 * Only attributes can have a paircompare registered, and
3466 * they can only be with the current REQUEST, and only
3467 * with the request pairs.
3469 if ((map->lhs->type != TMPL_TYPE_ATTR) ||
3470 (map->lhs->tmpl_request != REQUEST_CURRENT) ||
3471 (map->lhs->tmpl_list != PAIR_LIST_REQUEST)) {
3475 if (!radius_find_compare(map->lhs->tmpl_da)) return true;
3477 if (map->rhs->type == TMPL_TYPE_ATTR) {
3478 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
3483 if (map->rhs->type == TMPL_TYPE_REGEX) {
3484 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
3490 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
3495 if (map->op != T_OP_CMP_EQ) {
3496 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
3502 * Mark it as requiring a paircompare() call, instead of
3505 c->pass2_fixup = PASS2_PAIRCOMPARE;
3512 * Compile the RHS of update sections to xlat_exp_t
3514 static bool modcall_pass2_update(modgroup *g)
3518 for (map = g->map; map != NULL; map = map->next) {
3519 if (map->rhs->type == TMPL_TYPE_XLAT) {
3520 rad_assert(map->rhs->tmpl_xlat == NULL);
3523 * FIXME: compile to attribute && handle
3524 * the conversion in map_to_vp().
3526 if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3531 rad_assert(map->rhs->type != TMPL_TYPE_REGEX);
3534 * Deal with undefined attributes now.
3536 if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3537 if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
3540 if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3541 if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
3550 * Do a second-stage pass on compiling the modules.
3552 bool modcall_pass2(modcallable *mc)
3559 for (c = mc; c != NULL; c = c->next) {
3567 g = mod_callabletogroup(c);
3568 if (g->done_pass2) goto do_next;
3570 name2 = cf_section_name2(g->cs);
3572 c->debug_name = unlang_keyword[c->type];
3574 c->debug_name = talloc_asprintf(c, "update %s", name2);
3577 if (!modcall_pass2_update(g)) {
3580 g->done_pass2 = true;
3583 case MOD_XLAT: /* @todo: pre-parse xlat's */
3590 c->debug_name = c->name;
3591 break; /* do nothing */
3596 g = mod_callabletogroup(c);
3597 if (g->done_pass2) goto do_next;
3599 name2 = cf_section_name2(g->cs);
3600 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3603 * The compilation code takes care of
3604 * simplifying 'true' and 'false'
3605 * conditions. For others, we have to do
3606 * a second pass to parse && compile
3609 if (!((g->cond->type == COND_TYPE_TRUE) ||
3610 (g->cond->type == COND_TYPE_FALSE))) {
3611 if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
3616 if (!modcall_pass2(g->children)) return false;
3617 g->done_pass2 = true;
3623 g = mod_callabletogroup(c);
3624 if (g->done_pass2) goto do_next;
3626 name2 = cf_section_name2(g->cs);
3627 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3630 * We had &Foo-Bar, where Foo-Bar is
3631 * defined by a module.
3634 rad_assert(c->name != NULL);
3635 rad_assert(c->name[0] == '&');
3636 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3638 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3639 cf_section_name2_type(g->cs),
3640 REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
3642 char *spaces, *text;
3645 fr_canonicalize_error(g->cs, &spaces, &text, slen, fr_strerror());
3647 cf_log_err_cs(g->cs, "Syntax error");
3648 cf_log_err_cs(g->cs, "%s", c->name);
3649 cf_log_err_cs(g->cs, "%s^ %s", spaces, text);
3651 talloc_free(spaces);
3661 * Statically compile xlats
3663 if (g->vpt->type == TMPL_TYPE_XLAT) {
3664 if (!pass2_xlat_compile(cf_section_to_item(g->cs),
3665 &g->vpt, true, NULL)) {
3673 * Convert virtual &Attr-Foo to "%{Attr-Foo}"
3675 if ((g->vpt->type == TMPL_TYPE_ATTR) && g->vpt->tmpl_da->flags.virtual) {
3676 g->vpt->tmpl_xlat = xlat_from_tmpl_attr(g->vpt, g->vpt);
3677 g->vpt->type = TMPL_TYPE_XLAT_STRUCT;
3681 * We may have: switch Foo-Bar {
3683 * where Foo-Bar is an attribute defined
3684 * by a module. Since there's no leading
3685 * &, it's parsed as a literal. But if
3686 * we can parse it as an attribute,
3687 * switch to using that.
3689 if (g->vpt->type == TMPL_TYPE_LITERAL) {
3692 slen = tmpl_afrom_str(g->cs, &vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3693 REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
3694 if (slen < 0) goto parse_error;
3695 if (vpt->type == TMPL_TYPE_ATTR) {
3696 talloc_free(g->vpt);
3704 * Warn about old-style configuration.
3706 * DEPRECATED: switch User-Name { ...
3707 * ALLOWED : switch &User-Name { ...
3709 if ((g->vpt->type == TMPL_TYPE_ATTR) &&
3710 (c->name[0] != '&')) {
3711 WARN("%s[%d]: Please change %s to &%s",
3712 cf_section_filename(g->cs),
3713 cf_section_lineno(g->cs),
3718 if (!modcall_pass2(g->children)) return false;
3719 g->done_pass2 = true;
3723 g = mod_callabletogroup(c);
3724 if (g->done_pass2) goto do_next;
3726 name2 = cf_section_name2(g->cs);
3728 c->debug_name = unlang_keyword[c->type];
3730 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3733 rad_assert(c->parent != NULL);
3734 rad_assert(c->parent->type == MOD_SWITCH);
3737 * The statement may refer to an
3738 * attribute which doesn't exist until
3739 * all of the modules have been loaded.
3740 * Check for that now.
3742 if (!g->vpt && c->name &&
3743 (c->name[0] == '&') &&
3744 (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
3745 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3746 cf_section_name2_type(g->cs),
3747 REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
3748 if (slen < 0) goto parse_error;
3752 * We have "case {...}". There's no
3753 * argument, so we don't need to check
3756 if (!g->vpt) goto do_children;
3759 * Do type-specific checks on the case statement
3761 if (g->vpt->type == TMPL_TYPE_LITERAL) {
3764 f = mod_callabletogroup(mc->parent);
3765 rad_assert(f->vpt != NULL);
3768 * We're switching over an
3769 * attribute. Check that the
3772 if (f->vpt->type == TMPL_TYPE_ATTR) {
3773 rad_assert(f->vpt->tmpl_da != NULL);
3775 if (tmpl_cast_in_place(g->vpt, f->vpt->tmpl_da->type, f->vpt->tmpl_da) < 0) {
3776 cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
3785 if (g->vpt->type == TMPL_TYPE_ATTR_UNDEFINED) {
3786 if (!pass2_fixup_undefined(cf_section_to_item(g->cs), g->vpt)) {
3792 * Compile and sanity check xlat
3795 if (g->vpt->type == TMPL_TYPE_XLAT) {
3798 f = mod_callabletogroup(mc->parent);
3799 rad_assert(f->vpt != NULL);
3802 * Don't expand xlat's into an
3803 * attribute of a different type.
3805 if (f->vpt->type == TMPL_TYPE_ATTR) {
3806 if (!pass2_xlat_compile(cf_section_to_item(g->cs),
3807 &g->vpt, true, f->vpt->tmpl_da)) {
3811 if (!pass2_xlat_compile(cf_section_to_item(g->cs),
3812 &g->vpt, true, NULL)) {
3819 * Virtual attribute fixes for "case" statements, too.
3821 if ((g->vpt->type == TMPL_TYPE_ATTR) && g->vpt->tmpl_da->flags.virtual) {
3822 g->vpt->tmpl_xlat = xlat_from_tmpl_attr(g->vpt, g->vpt);
3823 g->vpt->type = TMPL_TYPE_XLAT_STRUCT;
3826 if (!modcall_pass2(g->children)) return false;
3827 g->done_pass2 = true;
3831 g = mod_callabletogroup(c);
3832 if (g->done_pass2) goto do_next;
3834 name2 = cf_section_name2(g->cs);
3835 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3838 * Already parsed, handle the children.
3840 if (g->vpt) goto check_children;
3843 * We had &Foo-Bar, where Foo-Bar is
3844 * defined by a module.
3846 rad_assert(c->name != NULL);
3847 rad_assert(c->name[0] == '&');
3848 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3851 * The statement may refer to an
3852 * attribute which doesn't exist until
3853 * all of the modules have been loaded.
3854 * Check for that now.
3856 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3857 REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
3858 if (slen < 0) goto parse_error;
3861 rad_assert((g->vpt->type == TMPL_TYPE_ATTR) || (g->vpt->type == TMPL_TYPE_LIST));
3862 if (g->vpt->tmpl_num != NUM_ALL) {
3863 cf_log_err_cs(g->cs, "MUST NOT use instance selectors in 'foreach'");
3866 if (!modcall_pass2(g->children)) return false;
3867 g->done_pass2 = true;
3871 c->debug_name = unlang_keyword[c->type];
3875 g = mod_callabletogroup(c);
3876 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], cf_section_name1(g->cs));
3881 case MOD_LOAD_BALANCE:
3882 case MOD_REDUNDANT_LOAD_BALANCE:
3883 c->debug_name = unlang_keyword[c->type];
3888 g = mod_callabletogroup(c);
3890 c->debug_name = mc->name; /* for authorize, etc. */
3892 } else if (c->type == MOD_GROUP) { /* for Auth-Type, etc. */
3893 char const *name1 = cf_section_name1(g->cs);
3895 if (strcmp(name1, unlang_keyword[c->type]) != 0) {
3896 name2 = cf_section_name2(g->cs);
3899 c->debug_name = name1;
3901 c->debug_name = talloc_asprintf(c, "%s %s", name1, name2);
3906 if (g->done_pass2) goto do_next;
3907 if (!modcall_pass2(g->children)) return false;
3908 g->done_pass2 = true;
3913 rad_assert(c->debug_name != NULL);
3919 void modcall_debug(modcallable *mc, int depth)
3926 for (this = mc; this != NULL; this = this->next) {
3927 switch (this->type) {
3932 modsingle *single = mod_callabletosingle(this);
3934 DEBUG("%.*s%s", depth, modcall_spaces,
3935 single->modinst->name);
3941 g = mod_callabletogroup(this);
3942 DEBUG("%.*s%s {", depth, modcall_spaces,
3943 unlang_keyword[this->type]);
3945 for (map = g->map; map != NULL; map = map->next) {
3946 map_prints(buffer, sizeof(buffer), map);
3947 DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
3950 DEBUG("%.*s}", depth, modcall_spaces);
3954 g = mod_callabletogroup(this);
3955 DEBUG("%.*s%s {", depth, modcall_spaces,
3956 unlang_keyword[this->type]);
3957 modcall_debug(g->children, depth + 1);
3958 DEBUG("%.*s}", depth, modcall_spaces);
3963 g = mod_callabletogroup(this);
3964 fr_cond_sprint(buffer, sizeof(buffer), g->cond);
3965 DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
3966 unlang_keyword[this->type], buffer);
3967 modcall_debug(g->children, depth + 1);
3968 DEBUG("%.*s}", depth, modcall_spaces);
3973 g = mod_callabletogroup(this);
3974 tmpl_prints(buffer, sizeof(buffer), g->vpt, NULL);
3975 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3976 unlang_keyword[this->type], buffer);
3977 modcall_debug(g->children, depth + 1);
3978 DEBUG("%.*s}", depth, modcall_spaces);
3983 g = mod_callabletogroup(this);
3984 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3985 unlang_keyword[this->type], this->name);
3986 modcall_debug(g->children, depth + 1);
3987 DEBUG("%.*s}", depth, modcall_spaces);
3991 DEBUG("%.*sbreak", depth, modcall_spaces);
3996 g = mod_callabletogroup(this);
3997 DEBUG("%.*s%s {", depth, modcall_spaces,
3998 unlang_keyword[this->type]);
3999 modcall_debug(g->children, depth + 1);
4000 DEBUG("%.*s}", depth, modcall_spaces);
4004 case MOD_LOAD_BALANCE:
4005 case MOD_REDUNDANT_LOAD_BALANCE:
4006 g = mod_callabletogroup(this);
4007 DEBUG("%.*s%s {", depth, modcall_spaces,
4008 unlang_keyword[this->type]);
4009 modcall_debug(g->children, depth + 1);
4010 DEBUG("%.*s}", depth, modcall_spaces);
4016 int modcall_pass2_condition(fr_cond_t *c)
4018 if (!fr_condition_walk(c, pass2_callback, NULL)) return -1;