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 },
177 * Compile action && rcode for later use.
179 static int compile_action(modcallable *c, CONF_PAIR *cp)
182 char const *attr, *value;
184 attr = cf_pair_attr(cp);
185 value = cf_pair_value(cp);
186 if (!value) return 0;
188 if (!strcasecmp(value, "return"))
189 action = MOD_ACTION_RETURN;
191 else if (!strcasecmp(value, "break"))
192 action = MOD_ACTION_RETURN;
194 else if (!strcasecmp(value, "reject"))
195 action = MOD_ACTION_REJECT;
197 else if (strspn(value, "0123456789")==strlen(value)) {
198 action = atoi(value);
201 * Don't allow priority zero, for future use.
203 if (action == 0) return 0;
205 cf_log_err_cp(cp, "Unknown action '%s'.\n",
210 if (strcasecmp(attr, "default") != 0) {
213 rcode = fr_str2int(mod_rcode_table, attr, -1);
216 "Unknown module rcode '%s'.\n",
220 c->actions[rcode] = action;
222 } else { /* set all unset values to the default */
225 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
226 if (!c->actions[i]) c->actions[i] = action;
233 /* Some short names for debugging output */
234 static char const * const comp2str[] = {
250 #ifdef HAVE_PTHREAD_H
252 * Lock the mutex for the module
254 static void safe_lock(module_instance_t *instance)
257 pthread_mutex_lock(instance->mutex);
261 * Unlock the mutex for the module
263 static void safe_unlock(module_instance_t *instance)
266 pthread_mutex_unlock(instance->mutex);
270 * No threads: these functions become NULL's.
272 #define safe_lock(foo)
273 #define safe_unlock(foo)
276 static rlm_rcode_t CC_HINT(nonnull) call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
279 int indent = request->log.indent;
282 * If the request should stop, refuse to do anything.
284 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
285 if (blocked) return RLM_MODULE_NOOP;
287 RDEBUG3("modsingle[%s]: calling %s (%s) for request %d",
288 comp2str[component], sp->modinst->name,
289 sp->modinst->entry->name, request->number);
290 request->log.indent = 0;
292 if (sp->modinst->force) {
293 request->rcode = sp->modinst->code;
298 * For logging unresponsive children.
300 request->module = sp->modinst->name;
302 safe_lock(sp->modinst);
303 request->rcode = sp->modinst->entry->module->methods[component](sp->modinst->insthandle, request);
304 safe_unlock(sp->modinst);
306 request->module = "";
309 * Wasn't blocked, and now is. Complain!
311 blocked = (request->master_state == REQUEST_STOP_PROCESSING);
313 RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
317 request->log.indent = indent;
318 RDEBUG3("modsingle[%s]: returned from %s (%s) for request %d",
319 comp2str[component], sp->modinst->name,
320 sp->modinst->entry->name, request->number);
322 return request->rcode;
325 static int default_component_results[RLM_COMPONENT_COUNT] = {
326 RLM_MODULE_REJECT, /* AUTH */
327 RLM_MODULE_NOTFOUND, /* AUTZ */
328 RLM_MODULE_NOOP, /* PREACCT */
329 RLM_MODULE_NOOP, /* ACCT */
330 RLM_MODULE_FAIL, /* SESS */
331 RLM_MODULE_NOOP, /* PRE_PROXY */
332 RLM_MODULE_NOOP, /* POST_PROXY */
333 RLM_MODULE_NOOP /* POST_AUTH */
336 RLM_MODULE_NOOP, /* RECV_COA_TYPE */
337 RLM_MODULE_NOOP /* SEND_COA_TYPE */
342 extern char const *unlang_keyword[];
344 char const *unlang_keyword[] = {
348 "load-balance group",
349 "redundant-load-balance group",
367 static char const modcall_spaces[] = " ";
369 #define MODCALL_STACK_MAX (32)
372 * Don't call the modules recursively. Instead, do them
373 * iteratively, and manage the call stack ourselves.
375 typedef struct modcall_stack_entry_t {
378 int unwind; /* unwind to this one if it exists */
380 } modcall_stack_entry_t;
383 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
384 modcall_stack_entry_t *entry);
387 * Call a child of a block.
389 static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
390 modcall_stack_entry_t *entry, modcallable *c,
393 modcall_stack_entry_t *next;
395 if (depth >= MODCALL_STACK_MAX) {
396 ERROR("Internal sanity check failed: module stack is too deep");
401 * Initialize the childs stack frame.
405 next->result = entry->result;
409 if (!modcall_recurse(request, component,
411 *result = RLM_MODULE_FAIL;
416 * Unwind back up the stack
418 if (next->unwind != 0) {
419 entry->unwind = next->unwind;
422 *result = next->result;
429 * Interpret the various types of blocks.
431 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
432 modcall_stack_entry_t *entry)
434 bool if_taken, was_if;
439 was_if = if_taken = false;
440 result = RLM_MODULE_UNKNOWN;
448 * Nothing more to do. Return the code and priority
449 * which was set by the caller.
453 rad_assert(c->debug_name != NULL); /* if this happens, all bets are off. */
456 * We've been asked to stop. Do so.
458 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
460 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
461 entry->result = RLM_MODULE_FAIL;
462 entry->priority = 9999;
468 * Handle "if" conditions.
470 if (c->type == MOD_IF) {
475 g = mod_callabletogroup(c);
476 rad_assert(g->cond != NULL);
478 RDEBUG2("%s %s{", unlang_keyword[c->type], c->name);
480 condition = radius_evaluate_cond(request, result, 0, g->cond);
483 REDEBUG("Failed retrieving values required to evaluate condition");
485 RDEBUG2("%s %s -> %s",
486 unlang_keyword[c->type],
487 c->name, condition ? "TRUE" : "FALSE");
491 * Didn't pass. Remember that.
500 * We took the "if". Go recurse into its' children.
508 * "else" if the previous "if" was taken.
509 * "if" if the previous if wasn't taken.
511 if (c->type == MOD_ELSIF) {
512 if (!was_if) goto elsif_error;
515 * Like MOD_ELSE, but allow for a later "else"
518 RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
519 unlang_keyword[c->type], request->number);
526 * Check the "if" condition.
532 * "else" for a preceding "if".
534 if (c->type == MOD_ELSE) {
535 if (!was_if) { /* error */
537 RDEBUG2("... skipping %s for request %d: No preceding \"if\"",
538 unlang_keyword[c->type], request->number);
543 RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
544 unlang_keyword[c->type], request->number);
551 * We need to process it. Go do that.
559 * We're no longer processing if/else/elsif. Reset the
560 * trackers for those conditions.
564 #endif /* WITH_UNLANG */
566 if (c->type == MOD_SINGLE) {
570 * Process a stand-alone child, and fall through
571 * to dealing with it's parent.
573 sp = mod_callabletosingle(c);
575 result = call_modsingle(c->method, sp, request);
576 RDEBUG2("[%s] = %s", c->name ? c->name : "",
577 fr_int2str(mod_rcode_table, result, "<invalid>"));
578 goto calculate_result;
583 * Update attribute(s)
585 if (c->type == MOD_UPDATE) {
587 modgroup *g = mod_callabletogroup(c);
588 value_pair_map_t *map;
592 for (map = g->map; map != NULL; map = map->next) {
593 rcode = map_to_request(request, map, map_to_vp, NULL);
595 result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
598 goto calculate_result;
602 result = RLM_MODULE_NOOP;
604 goto calculate_result;
608 * Loop over a set of attributes.
610 if (c->type == MOD_FOREACH) {
611 int i, foreach_depth = -1;
612 VALUE_PAIR *vps, *vp;
613 modcall_stack_entry_t *next = NULL;
615 modgroup *g = mod_callabletogroup(c);
617 if (depth >= MODCALL_STACK_MAX) {
618 ERROR("Internal sanity check failed: module stack is too deep");
623 * Figure out how deep we are in nesting by looking at request_data
626 for (i = 0; i < 8; i++) {
627 if (!request_data_reference(request, (void *)radius_get_vp, i)) {
633 if (foreach_depth < 0) {
634 REDEBUG("foreach Nesting too deep!");
635 result = RLM_MODULE_FAIL;
636 goto calculate_result;
640 * Copy the VPs from the original request, this ensures deterministic
641 * behaviour if someone decides to add or remove VPs in the set were
644 if (tmpl_copy_vps(request, &vps, request, g->vpt) < 0) { /* nothing to loop over */
646 result = RLM_MODULE_NOOP;
648 goto calculate_result;
651 rad_assert(vps != NULL);
652 fr_cursor_init(©, &vps);
654 RDEBUG2("foreach %s ", c->name);
657 * This is the actual body of the foreach loop
659 for (vp = fr_cursor_first(©);
661 vp = fr_cursor_next(©)) {
663 if (fr_debug_flag >= 2) {
666 vp_prints_value(buffer, sizeof(buffer), vp, '"');
667 RDEBUG2("# Foreach-Variable-%d = %s", foreach_depth, buffer);
672 * Add the vp to the request, so that
673 * xlat.c, xlat_foreach() can find it.
675 request_data_add(request, (void *)radius_get_vp, foreach_depth, &vp, false);
678 * Initialize the childs stack frame.
681 next->c = g->children;
682 next->result = entry->result;
686 if (!modcall_recurse(request, component, depth + 1, next)) {
691 * We've unwound to the enclosing
692 * "foreach". Stop the unwinding.
694 if (next->unwind == MOD_FOREACH) {
699 * Unwind all the way.
701 if (next->unwind == MOD_RETURN) {
702 entry->unwind = MOD_RETURN;
705 } /* loop over VPs */
708 * Free the copied vps and the request data
709 * If we don't remove the request data, something could call
710 * the xlat outside of a foreach loop and trigger a segv.
713 request_data_get(request, (void *)radius_get_vp, foreach_depth);
715 rad_assert(next != NULL);
716 result = next->result;
717 priority = next->priority;
719 goto calculate_result;
723 * Break out of a "foreach" loop, or return from a nested
726 if ((c->type == MOD_BREAK) || (c->type == MOD_RETURN)) {
730 RDEBUG2("%s", unlang_keyword[c->type]);
732 for (i = 8; i >= 0; i--) {
733 copy_p = request_data_get(request, (void *)radius_get_vp, i);
735 if (c->type == MOD_BREAK) {
736 RDEBUG2("# break Foreach-Variable-%d", i);
743 * Leave result / priority on the stack, and stop processing the section.
745 entry->unwind = c->type;
749 #endif /* WITH_UNLANG */
752 * Child is a group that has children of it's own.
754 if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
756 || (c->type == MOD_CASE)
764 g = mod_callabletogroup(c);
767 * This should really have been caught in the
768 * compiler, and the node never generated. But
769 * doing that requires changing it's API so that
770 * it returns a flag instead of the compiled
774 RDEBUG2("%s { ... } # empty sub-section is ignored", c->name);
779 modcall_child(request, component,
780 depth + 1, entry, g->children,
783 goto calculate_result;
787 if (c->type == MOD_SWITCH) {
788 modcallable *this, *found, *null_case;
792 value_pair_map_t map;
793 value_pair_tmpl_t vpt;
797 g = mod_callabletogroup(c);
799 memset(&cond, 0, sizeof(cond));
800 memset(&map, 0, sizeof(map));
802 cond.type = COND_TYPE_MAP;
803 cond.data.map = ↦
805 map.op = T_OP_CMP_EQ;
806 map.ci = cf_section_to_item(g->cs);
808 rad_assert(g->vpt != NULL);
810 null_case = found = NULL;
814 * The attribute doesn't exist. We can skip
815 * directly to the default 'case' statement.
817 if ((g->vpt->type == TMPL_TYPE_ATTR) && (tmpl_find_vp(NULL, request, g->vpt) < 0)) {
819 for (this = g->children; this; this = this->next) {
820 rad_assert(this->type == MOD_CASE);
822 h = mod_callabletogroup(this);
823 if (h->vpt) continue;
833 * Expand the template if necessary, so that it
834 * is evaluated once instead of for each 'case'
837 if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
838 (g->vpt->type == TMPL_TYPE_XLAT) ||
839 (g->vpt->type == TMPL_TYPE_EXEC)) {
842 if (tmpl_aexpand(request, &p, request, g->vpt, NULL, NULL) < 0) goto find_null_case;
844 tmpl_init(&vpt, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
848 * Find either the exact matching name, or the
849 * "case {...}" statement.
851 for (this = g->children; this; this = this->next) {
852 rad_assert(this->type == MOD_CASE);
854 h = mod_callabletogroup(this);
857 * Remember the default case
860 if (!null_case) null_case = this;
865 * If we're switching over an attribute
866 * AND we haven't pre-parsed the data for
867 * the case statement, then cast the data
868 * to the type of the attribute.
870 if ((g->vpt->type == TMPL_TYPE_ATTR) &&
871 (h->vpt->type != TMPL_TYPE_DATA)) {
874 cond.cast = g->vpt->tmpl_da;
877 * Remove unnecessary casting.
879 if ((h->vpt->type == TMPL_TYPE_ATTR) &&
880 (g->vpt->tmpl_da->type == h->vpt->tmpl_da->type)) {
885 * Use the pre-expanded string.
887 } else if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
888 (g->vpt->type == TMPL_TYPE_XLAT) ||
889 (g->vpt->type == TMPL_TYPE_EXEC)) {
895 * Else evaluate the 'switch' statement.
903 if (radius_evaluate_map(request, RLM_MODULE_UNKNOWN, 0,
910 if (!found) found = null_case;
913 talloc_free(data.ptr);
914 modcall_child(request, component, depth + 1, entry, found, &result);
916 goto calculate_result;
920 if ((c->type == MOD_LOAD_BALANCE) ||
921 (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
923 modcallable *this, *found;
928 g = mod_callabletogroup(c);
930 rad_assert(g->children != NULL);
933 * Choose a child at random.
935 for (this = g->children; this; this = this->next) {
938 if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
945 if (c->type == MOD_LOAD_BALANCE) {
946 modcall_child(request, component,
947 depth + 1, entry, found,
954 modcall_child(request, component,
955 depth + 1, entry, this,
957 if (this->actions[result] == MOD_ACTION_RETURN) {
963 if (!this) this = g->children;
964 } while (this != found);
967 goto calculate_result;
968 } /* MOD_LOAD_BALANCE */
971 * Reference another virtual server.
973 * This should really be deleted, and replaced with a
974 * more abstracted / functional version.
976 if (c->type == MOD_REFERENCE) {
977 modref *mr = mod_callabletoref(c);
978 char const *server = request->server;
980 if (server == mr->ref_name) {
981 RWDEBUG("Suppressing recursive call to server %s", server);
985 request->server = mr->ref_name;
986 RDEBUG("server %s { # nested call", mr->ref_name);
987 result = indexed_modcall(component, 0, request);
988 RDEBUG("} # server %s with nested call", mr->ref_name);
989 request->server = server;
990 goto calculate_result;
991 } /* MOD_REFERENCE */
994 * xlat a string without doing anything else
996 * This should really be deleted, and replaced with a
997 * more abstracted / functional version.
999 if (c->type == MOD_XLAT) {
1000 modxlat *mx = mod_callabletoxlat(c);
1004 radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
1006 RDEBUG("`%s`", mx->xlat_name);
1007 radius_exec_program(NULL, 0, NULL, request, mx->xlat_name, request->packet->vps,
1008 false, true, EXEC_TIMEOUT);
1015 * Add new module types here.
1020 RDEBUG("(%s, %d) ? (%s, %d)",
1021 fr_int2str(mod_rcode_table, result, "<invalid>"),
1023 fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
1028 rad_assert(result != RLM_MODULE_UNKNOWN);
1031 * The child's action says return. Do so.
1033 if ((c->actions[result] == MOD_ACTION_RETURN) &&
1035 entry->result = result;
1040 * If "reject", break out of the loop and return
1043 if (c->actions[result] == MOD_ACTION_REJECT) {
1044 entry->result = RLM_MODULE_REJECT;
1049 * The array holds a default priority for this return
1050 * code. Grab it in preference to any unset priority.
1053 priority = c->actions[result];
1057 * We're higher than any previous priority, remember this
1058 * return code and priority.
1060 if (priority > entry->priority) {
1061 entry->result = result;
1062 entry->priority = priority;
1067 * If we're processing a "case" statement, we return once
1068 * it's done, rather than going to the next "case" statement.
1070 if (c->type == MOD_CASE) goto finish;
1074 * If we've been told to stop processing
1077 if (entry->unwind == MOD_BREAK) {
1078 RDEBUG2("# unwind to enclosing foreach");
1083 if (entry->unwind == MOD_RETURN) {
1088 entry->c = entry->c->next;
1090 if (entry->c) goto redo;
1101 /** Call a module, iteratively, with a local stack, rather than recursively
1103 * What did Paul Graham say about Lisp...?
1105 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1107 modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1110 memset(stack, 0, sizeof(stack));
1113 * Set up the initial stack frame.
1116 stack[0].result = default_component_results[component];
1117 stack[0].priority = 0;
1118 stack[0].unwind = 0;
1121 * Call the main handler.
1123 if (!modcall_recurse(request, component, 0, &stack[0])) {
1124 return RLM_MODULE_FAIL;
1128 * Return the result.
1130 return stack[0].result;
1135 static char const *action2str(int action)
1137 static char buf[32];
1138 if(action==MOD_ACTION_RETURN)
1140 if(action==MOD_ACTION_REJECT)
1142 snprintf(buf, sizeof buf, "%d", action);
1146 /* If you suspect a bug in the parser, you'll want to use these dump
1147 * functions. dump_tree should reproduce a whole tree exactly as it was found
1148 * in radiusd.conf, but in long form (all actions explicitly defined) */
1149 static void dump_mc(modcallable *c, int indent)
1153 if(c->type==MOD_SINGLE) {
1154 modsingle *single = mod_callabletosingle(c);
1155 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1156 single->modinst->name);
1157 } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1158 modgroup *g = mod_callabletogroup(c);
1160 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1161 unlang_keyword[c->type]);
1162 for(p = g->children;p;p = p->next)
1163 dump_mc(p, indent+1);
1164 } /* else ignore it for now */
1166 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1167 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1168 fr_int2str(mod_rcode_table, i, "<invalid>"),
1169 action2str(c->actions[i]));
1172 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1175 static void dump_tree(rlm_components_t comp, modcallable *c)
1177 DEBUG("[%s]", comp2str[comp]);
1181 #define dump_tree(a, b)
1184 /* These are the default actions. For each component, the group{} block
1185 * behaves like the code from the old module_*() function. redundant{} and
1186 * append{} are based on my guesses of what they will be used for. --Pac. */
1188 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1194 MOD_ACTION_RETURN, /* reject */
1196 MOD_ACTION_RETURN, /* ok */
1197 MOD_ACTION_RETURN, /* handled */
1199 MOD_ACTION_RETURN, /* userlock */
1200 MOD_ACTION_RETURN, /* notfound */
1206 MOD_ACTION_RETURN, /* reject */
1208 MOD_ACTION_RETURN, /* ok */
1209 MOD_ACTION_RETURN, /* handled */
1210 MOD_ACTION_RETURN, /* invalid */
1211 MOD_ACTION_RETURN, /* userlock */
1212 MOD_ACTION_RETURN, /* notfound */
1213 MOD_ACTION_RETURN, /* noop */
1214 MOD_ACTION_RETURN /* updated */
1218 MOD_ACTION_RETURN, /* reject */
1220 MOD_ACTION_RETURN, /* ok */
1221 MOD_ACTION_RETURN, /* handled */
1222 MOD_ACTION_RETURN, /* invalid */
1223 MOD_ACTION_RETURN, /* userlock */
1225 MOD_ACTION_RETURN, /* noop */
1226 MOD_ACTION_RETURN /* updated */
1233 MOD_ACTION_RETURN, /* reject */
1234 MOD_ACTION_RETURN, /* fail */
1236 MOD_ACTION_RETURN, /* handled */
1237 MOD_ACTION_RETURN, /* invalid */
1238 MOD_ACTION_RETURN, /* userlock */
1245 MOD_ACTION_RETURN, /* reject */
1247 MOD_ACTION_RETURN, /* ok */
1248 MOD_ACTION_RETURN, /* handled */
1249 MOD_ACTION_RETURN, /* invalid */
1250 MOD_ACTION_RETURN, /* userlock */
1251 MOD_ACTION_RETURN, /* notfound */
1252 MOD_ACTION_RETURN, /* noop */
1253 MOD_ACTION_RETURN /* updated */
1257 MOD_ACTION_RETURN, /* reject */
1259 MOD_ACTION_RETURN, /* ok */
1260 MOD_ACTION_RETURN, /* handled */
1261 MOD_ACTION_RETURN, /* invalid */
1262 MOD_ACTION_RETURN, /* userlock */
1264 MOD_ACTION_RETURN, /* noop */
1265 MOD_ACTION_RETURN /* updated */
1272 MOD_ACTION_RETURN, /* reject */
1273 MOD_ACTION_RETURN, /* fail */
1275 MOD_ACTION_RETURN, /* handled */
1276 MOD_ACTION_RETURN, /* invalid */
1277 MOD_ACTION_RETURN, /* userlock */
1278 MOD_ACTION_RETURN, /* notfound */
1284 MOD_ACTION_RETURN, /* reject */
1286 MOD_ACTION_RETURN, /* ok */
1287 MOD_ACTION_RETURN, /* handled */
1288 MOD_ACTION_RETURN, /* invalid */
1289 MOD_ACTION_RETURN, /* userlock */
1290 MOD_ACTION_RETURN, /* notfound */
1291 MOD_ACTION_RETURN, /* noop */
1292 MOD_ACTION_RETURN /* updated */
1296 MOD_ACTION_RETURN, /* reject */
1298 MOD_ACTION_RETURN, /* ok */
1299 MOD_ACTION_RETURN, /* handled */
1300 MOD_ACTION_RETURN, /* invalid */
1301 MOD_ACTION_RETURN, /* userlock */
1303 MOD_ACTION_RETURN, /* noop */
1304 MOD_ACTION_RETURN /* updated */
1311 MOD_ACTION_RETURN, /* reject */
1312 MOD_ACTION_RETURN, /* fail */
1314 MOD_ACTION_RETURN, /* handled */
1315 MOD_ACTION_RETURN, /* invalid */
1316 MOD_ACTION_RETURN, /* userlock */
1317 MOD_ACTION_RETURN, /* notfound */
1325 MOD_ACTION_RETURN, /* ok */
1326 MOD_ACTION_RETURN, /* handled */
1335 MOD_ACTION_RETURN, /* reject */
1337 MOD_ACTION_RETURN, /* ok */
1338 MOD_ACTION_RETURN, /* handled */
1339 MOD_ACTION_RETURN, /* invalid */
1340 MOD_ACTION_RETURN, /* userlock */
1342 MOD_ACTION_RETURN, /* noop */
1343 MOD_ACTION_RETURN /* updated */
1350 MOD_ACTION_RETURN, /* reject */
1352 MOD_ACTION_RETURN, /* ok */
1353 MOD_ACTION_RETURN, /* handled */
1354 MOD_ACTION_RETURN, /* invalid */
1355 MOD_ACTION_RETURN, /* userlock */
1356 MOD_ACTION_RETURN, /* notfound */
1357 MOD_ACTION_RETURN, /* noop */
1358 MOD_ACTION_RETURN /* updated */
1362 MOD_ACTION_RETURN, /* reject */
1364 MOD_ACTION_RETURN, /* ok */
1365 MOD_ACTION_RETURN, /* handled */
1366 MOD_ACTION_RETURN, /* invalid */
1367 MOD_ACTION_RETURN, /* userlock */
1368 MOD_ACTION_RETURN, /* notfound */
1369 MOD_ACTION_RETURN, /* noop */
1370 MOD_ACTION_RETURN /* updated */
1374 MOD_ACTION_RETURN, /* reject */
1376 MOD_ACTION_RETURN, /* ok */
1377 MOD_ACTION_RETURN, /* handled */
1378 MOD_ACTION_RETURN, /* invalid */
1379 MOD_ACTION_RETURN, /* userlock */
1380 MOD_ACTION_RETURN, /* notfound */
1381 MOD_ACTION_RETURN, /* noop */
1382 MOD_ACTION_RETURN /* updated */
1389 MOD_ACTION_RETURN, /* reject */
1390 MOD_ACTION_RETURN, /* fail */
1392 MOD_ACTION_RETURN, /* handled */
1393 MOD_ACTION_RETURN, /* invalid */
1394 MOD_ACTION_RETURN, /* userlock */
1401 MOD_ACTION_RETURN, /* reject */
1403 MOD_ACTION_RETURN, /* ok */
1404 MOD_ACTION_RETURN, /* handled */
1405 MOD_ACTION_RETURN, /* invalid */
1406 MOD_ACTION_RETURN, /* userlock */
1407 MOD_ACTION_RETURN, /* notfound */
1408 MOD_ACTION_RETURN, /* noop */
1409 MOD_ACTION_RETURN /* updated */
1413 MOD_ACTION_RETURN, /* reject */
1415 MOD_ACTION_RETURN, /* ok */
1416 MOD_ACTION_RETURN, /* handled */
1417 MOD_ACTION_RETURN, /* invalid */
1418 MOD_ACTION_RETURN, /* userlock */
1420 MOD_ACTION_RETURN, /* noop */
1421 MOD_ACTION_RETURN /* updated */
1428 MOD_ACTION_RETURN, /* reject */
1429 MOD_ACTION_RETURN, /* fail */
1431 MOD_ACTION_RETURN, /* handled */
1432 MOD_ACTION_RETURN, /* invalid */
1433 MOD_ACTION_RETURN, /* userlock */
1440 MOD_ACTION_RETURN, /* reject */
1442 MOD_ACTION_RETURN, /* ok */
1443 MOD_ACTION_RETURN, /* handled */
1444 MOD_ACTION_RETURN, /* invalid */
1445 MOD_ACTION_RETURN, /* userlock */
1446 MOD_ACTION_RETURN, /* notfound */
1447 MOD_ACTION_RETURN, /* noop */
1448 MOD_ACTION_RETURN /* updated */
1452 MOD_ACTION_RETURN, /* reject */
1454 MOD_ACTION_RETURN, /* ok */
1455 MOD_ACTION_RETURN, /* handled */
1456 MOD_ACTION_RETURN, /* invalid */
1457 MOD_ACTION_RETURN, /* userlock */
1459 MOD_ACTION_RETURN, /* noop */
1460 MOD_ACTION_RETURN /* updated */
1467 MOD_ACTION_RETURN, /* reject */
1468 MOD_ACTION_RETURN, /* fail */
1470 MOD_ACTION_RETURN, /* handled */
1471 MOD_ACTION_RETURN, /* invalid */
1472 MOD_ACTION_RETURN, /* userlock */
1479 MOD_ACTION_RETURN, /* reject */
1481 MOD_ACTION_RETURN, /* ok */
1482 MOD_ACTION_RETURN, /* handled */
1483 MOD_ACTION_RETURN, /* invalid */
1484 MOD_ACTION_RETURN, /* userlock */
1485 MOD_ACTION_RETURN, /* notfound */
1486 MOD_ACTION_RETURN, /* noop */
1487 MOD_ACTION_RETURN /* updated */
1491 MOD_ACTION_RETURN, /* reject */
1493 MOD_ACTION_RETURN, /* ok */
1494 MOD_ACTION_RETURN, /* handled */
1495 MOD_ACTION_RETURN, /* invalid */
1496 MOD_ACTION_RETURN, /* userlock */
1498 MOD_ACTION_RETURN, /* noop */
1499 MOD_ACTION_RETURN /* updated */
1508 MOD_ACTION_RETURN, /* reject */
1509 MOD_ACTION_RETURN, /* fail */
1511 MOD_ACTION_RETURN, /* handled */
1512 MOD_ACTION_RETURN, /* invalid */
1513 MOD_ACTION_RETURN, /* userlock */
1520 MOD_ACTION_RETURN, /* reject */
1522 MOD_ACTION_RETURN, /* ok */
1523 MOD_ACTION_RETURN, /* handled */
1524 MOD_ACTION_RETURN, /* invalid */
1525 MOD_ACTION_RETURN, /* userlock */
1526 MOD_ACTION_RETURN, /* notfound */
1527 MOD_ACTION_RETURN, /* noop */
1528 MOD_ACTION_RETURN /* updated */
1532 MOD_ACTION_RETURN, /* reject */
1534 MOD_ACTION_RETURN, /* ok */
1535 MOD_ACTION_RETURN, /* handled */
1536 MOD_ACTION_RETURN, /* invalid */
1537 MOD_ACTION_RETURN, /* userlock */
1539 MOD_ACTION_RETURN, /* noop */
1540 MOD_ACTION_RETURN /* updated */
1547 MOD_ACTION_RETURN, /* reject */
1548 MOD_ACTION_RETURN, /* fail */
1550 MOD_ACTION_RETURN, /* handled */
1551 MOD_ACTION_RETURN, /* invalid */
1552 MOD_ACTION_RETURN, /* userlock */
1559 MOD_ACTION_RETURN, /* reject */
1561 MOD_ACTION_RETURN, /* ok */
1562 MOD_ACTION_RETURN, /* handled */
1563 MOD_ACTION_RETURN, /* invalid */
1564 MOD_ACTION_RETURN, /* userlock */
1565 MOD_ACTION_RETURN, /* notfound */
1566 MOD_ACTION_RETURN, /* noop */
1567 MOD_ACTION_RETURN /* updated */
1571 MOD_ACTION_RETURN, /* reject */
1573 MOD_ACTION_RETURN, /* ok */
1574 MOD_ACTION_RETURN, /* handled */
1575 MOD_ACTION_RETURN, /* invalid */
1576 MOD_ACTION_RETURN, /* userlock */
1578 MOD_ACTION_RETURN, /* noop */
1579 MOD_ACTION_RETURN /* updated */
1585 /** Validate and fixup a map that's part of an update section.
1587 * @param map to validate.
1588 * @param ctx data to pass to fixup function (currently unused).
1589 * @return 0 if valid else -1.
1591 int modcall_fixup_update(value_pair_map_t *map, UNUSED void *ctx)
1593 CONF_PAIR *cp = cf_item_to_pair(map->ci);
1596 * Anal-retentive checks.
1598 if (DEBUG_ENABLED3) {
1599 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->name[0] != '&')) {
1600 WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
1601 cf_pair_filename(cp), cf_pair_lineno(cp),
1602 map->lhs->name, fr_int2str(fr_tokens, map->op, "<INVALID>"));
1605 if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->name[0] != '&')) {
1606 WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
1607 cf_pair_filename(cp), cf_pair_lineno(cp),
1608 fr_int2str(fr_tokens, map->op, "<INVALID>"), map->rhs->name);
1613 * Values used by unary operators should be literal ANY
1615 * We then free the template and alloc a NULL one instead.
1617 if (map->op == T_OP_CMP_FALSE) {
1618 if ((map->rhs->type != TMPL_TYPE_LITERAL) || (strcmp(map->rhs->name, "ANY") != 0)) {
1619 WARN("%s[%d] Wildcard deletion MUST use '!* ANY'",
1620 cf_pair_filename(cp), cf_pair_lineno(cp));
1623 tmpl_free(&map->rhs);
1625 map->rhs = tmpl_alloc(map, TMPL_TYPE_NULL, NULL, 0);
1629 * Lots of sanity checks for insane people...
1633 * What exactly where you expecting to happen here?
1635 if ((map->lhs->type == TMPL_TYPE_ATTR) &&
1636 (map->rhs->type == TMPL_TYPE_LIST)) {
1637 cf_log_err(map->ci, "Can't copy list into an attribute");
1642 * Depending on the attribute type, some operators are disallowed.
1644 if (map->lhs->type == TMPL_TYPE_ATTR) {
1647 cf_log_err(map->ci, "Invalid operator for attribute");
1656 case T_OP_CMP_FALSE:
1662 if (map->lhs->type == TMPL_TYPE_LIST) {
1664 * Can't copy an xlat expansion or literal into a list,
1665 * we don't know what type of attribute we'd need
1668 * The only exception is where were using a unary
1671 if (map->op != T_OP_CMP_FALSE) switch (map->rhs->type) {
1672 case TMPL_TYPE_XLAT:
1673 case TMPL_TYPE_LITERAL:
1674 cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
1682 * Only += and :=, and !* operators are supported
1686 case T_OP_CMP_FALSE:
1690 if ((map->rhs->type != TMPL_TYPE_LIST) &&
1691 (map->rhs->type != TMPL_TYPE_EXEC)) {
1692 cf_log_err(map->ci, "Invalid source for list assignment '%s += ...'", map->lhs->name);
1698 if (map->rhs->type == TMPL_TYPE_EXEC) {
1699 WARN("%s[%d] Please change ':=' to '=' for list assignment",
1700 cf_pair_filename(cp), cf_pair_lineno(cp));
1703 if (map->rhs->type != TMPL_TYPE_LIST) {
1704 cf_log_err(map->ci, "Invalid source for list assignment '%s := ...'", map->lhs->name);
1710 if (map->rhs->type != TMPL_TYPE_EXEC) {
1711 cf_log_err(map->ci, "Invalid source for list assignment '%s = ...'", map->lhs->name);
1717 cf_log_err(map->ci, "Operator \"%s\" not allowed for list assignment",
1718 fr_int2str(fr_tokens, map->op, "<INVALID>"));
1724 * If the map has a unary operator there's no further
1725 * processing we need to, as RHS is unused.
1727 if (map->op == T_OP_CMP_FALSE) return 0;
1730 * If LHS is an attribute, and RHS is a literal, we can
1731 * preparse the information into a TMPL_TYPE_DATA.
1733 * Unless it's a unary operator in which case we
1736 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->rhs->type == TMPL_TYPE_LITERAL)) {
1738 * It's a literal string, just copy it.
1739 * Don't escape anything.
1741 if (!cf_new_escape &&
1742 (map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
1743 (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
1744 tmpl_cast_in_place_str(map->rhs);
1746 if (!tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da)) {
1747 cf_log_err(map->ci, "%s", fr_strerror());
1752 * Fixup LHS da if it doesn't match the type
1755 if (map->lhs->tmpl_da->type != map->rhs->tmpl_data_type) {
1756 DICT_ATTR const *da;
1758 da = dict_attrbytype(map->lhs->tmpl_da->attr, map->lhs->tmpl_da->vendor,
1759 map->rhs->tmpl_data_type);
1761 fr_strerror_printf("Cannot find %s variant of attribute \"%s\"",
1762 fr_int2str(dict_attr_types, map->rhs->tmpl_data_type,
1763 "<INVALID>"), map->lhs->tmpl_da->name);
1766 map->lhs->tmpl_da = da;
1769 } /* else we can't precompile the data */
1776 static modcallable *do_compile_modupdate(modcallable *parent, rlm_components_t component,
1777 CONF_SECTION *cs, char const *name2)
1781 modcallable *csingle;
1783 value_pair_map_t *head;
1786 * This looks at cs->name2 to determine which list to update
1788 rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, modcall_fixup_update, NULL, 128);
1789 if (rcode < 0) return NULL; /* message already printed */
1791 cf_log_err_cs(cs, "'update' sections cannot be empty");
1795 g = talloc_zero(parent, modgroup);
1796 csingle = mod_grouptocallable(g);
1798 csingle->parent = parent;
1799 csingle->next = NULL;
1802 csingle->name = name2;
1806 csingle->type = MOD_UPDATE;
1807 csingle->method = component;
1809 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1810 sizeof(csingle->actions));
1812 g->grouptype = GROUPTYPE_SIMPLE;
1815 g->map = talloc_steal(g, head);
1821 static modcallable *do_compile_modswitch (modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1826 bool had_seen_default = false;
1827 modcallable *csingle;
1830 value_pair_tmpl_t *vpt;
1832 name2 = cf_section_name2(cs);
1834 cf_log_err_cs(cs, "You must specify a variable to switch over for 'switch'");
1838 if (!cf_item_find_next(cs, NULL)) {
1839 cf_log_err_cs(cs, "'switch' statements cannot be empty");
1844 * Create the template. If we fail, AND it's a bare word
1845 * with &Foo-Bar, it MAY be an attribute defined by a
1846 * module. Allow it for now. The pass2 checks below
1849 type = cf_section_name2_type(cs);
1850 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1851 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1852 char *spaces, *text;
1854 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1856 cf_log_err_cs(cs, "Syntax error");
1857 cf_log_err_cs(cs, "%s", name2);
1858 cf_log_err_cs(cs, "%s^ %s", spaces, text);
1860 talloc_free(spaces);
1867 * Otherwise a NULL vpt may refer to an attribute defined
1868 * by a module. That is checked in pass 2.
1871 if (vpt->type == TMPL_TYPE_LIST) {
1872 cf_log_err_cs(cs, "Syntax error: Cannot switch over list '%s'", name2);
1878 * Walk through the children of the switch section,
1879 * ensuring that they're all 'case' statements
1881 for (ci = cf_item_find_next(cs, NULL);
1883 ci = cf_item_find_next(cs, ci)) {
1884 CONF_SECTION *subcs;
1887 if (!cf_item_is_section(ci)) {
1888 if (!cf_item_is_pair(ci)) continue;
1890 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1895 subcs = cf_item_to_section(ci); /* can't return NULL */
1896 name1 = cf_section_name1(subcs);
1898 if (strcmp(name1, "case") != 0) {
1899 cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1904 name2 = cf_section_name2(subcs);
1906 if (!had_seen_default) {
1907 had_seen_default = true;
1911 cf_log_err(ci, "Cannot have two 'default' case statements");
1917 csingle = do_compile_modgroup(parent, component, cs,
1926 g = mod_callabletogroup(csingle);
1927 g->vpt = talloc_steal(g, vpt);
1932 static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1936 modcallable *csingle;
1938 value_pair_tmpl_t *vpt;
1940 if (!parent || (parent->type != MOD_SWITCH)) {
1941 cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
1946 * case THING means "match THING"
1947 * case means "match anything"
1949 name2 = cf_section_name2(cs);
1954 type = cf_section_name2_type(cs);
1956 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1957 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1958 char *spaces, *text;
1960 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1962 cf_log_err_cs(cs, "Syntax error");
1963 cf_log_err_cs(cs, "%s", name2);
1964 cf_log_err_cs(cs, "%s^ %s", spaces, text);
1966 talloc_free(spaces);
1972 if (vpt->type == TMPL_TYPE_LIST) {
1973 cf_log_err_cs(cs, "Syntax error: Cannot match list '%s'", name2);
1978 * Otherwise a NULL vpt may refer to an attribute defined
1979 * by a module. That is checked in pass 2.
1986 csingle = do_compile_modgroup(parent, component, cs,
1996 * The interpretor expects this to be NULL for the
1997 * default case. do_compile_modgroup sets it to name2,
1998 * unless name2 is NULL, in which case it sets it to name1.
2000 csingle->name = name2;
2002 g = mod_callabletogroup(csingle);
2003 g->vpt = talloc_steal(g, vpt);
2006 * Set all of it's codes to return, so that
2007 * when we pick a 'case' statement, we don't
2008 * fall through to processing the next one.
2010 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2011 csingle->actions[i] = MOD_ACTION_RETURN;
2017 static modcallable *do_compile_modforeach(modcallable *parent,
2018 rlm_components_t component, CONF_SECTION *cs)
2022 modcallable *csingle;
2025 value_pair_tmpl_t *vpt;
2027 name2 = cf_section_name2(cs);
2030 "You must specify an attribute to loop over in 'foreach'");
2034 if (!cf_item_find_next(cs, NULL)) {
2035 cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
2040 * Create the template. If we fail, AND it's a bare word
2041 * with &Foo-Bar, it MAY be an attribute defined by a
2042 * module. Allow it for now. The pass2 checks below
2045 type = cf_section_name2_type(cs);
2046 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
2047 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
2048 char *spaces, *text;
2050 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
2052 cf_log_err_cs(cs, "Syntax error");
2053 cf_log_err_cs(cs, "%s", name2);
2054 cf_log_err_cs(cs, "%s^ %s", spaces, text);
2056 talloc_free(spaces);
2063 * If we don't have a negative return code, we must have a vpt
2064 * (mostly to quiet coverity).
2068 if ((vpt->type != TMPL_TYPE_ATTR) && (vpt->type != TMPL_TYPE_LIST)) {
2069 cf_log_err_cs(cs, "MUST use attribute or list reference in 'foreach'");
2074 * Fix up the template to iterate over all instances of
2075 * the attribute. In a perfect consistent world, users would do
2076 * foreach &attr[*], but that's taking the consistency thing a bit far.
2078 vpt->tmpl_num = NUM_ALL;
2080 csingle = do_compile_modgroup(parent, component, cs,
2081 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2089 g = mod_callabletogroup(csingle);
2095 static modcallable *do_compile_modbreak(modcallable *parent,
2096 rlm_components_t component, CONF_ITEM const *ci)
2098 CONF_SECTION const *cs = NULL;
2100 for (cs = cf_item_parent(ci);
2102 cs = cf_item_parent(cf_section_to_item(cs))) {
2103 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
2109 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
2113 return do_compile_modgroup(parent, component, NULL,
2114 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2119 static modcallable *do_compile_modserver(modcallable *parent,
2120 rlm_components_t component, CONF_ITEM *ci,
2125 modcallable *csingle;
2126 CONF_SECTION *subcs;
2129 subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
2131 cf_log_err(ci, "Server %s has no %s section",
2132 server, comp2str[component]);
2136 mr = talloc_zero(parent, modref);
2138 csingle = mod_reftocallable(mr);
2139 csingle->parent = parent;
2140 csingle->next = NULL;
2141 csingle->name = name;
2142 csingle->type = MOD_REFERENCE;
2143 csingle->method = component;
2145 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2146 sizeof(csingle->actions));
2148 mr->ref_name = strdup(server);
2154 static modcallable *do_compile_modxlat(modcallable *parent,
2155 rlm_components_t component, char const *fmt)
2157 modcallable *csingle;
2160 mx = talloc_zero(parent, modxlat);
2162 csingle = mod_xlattocallable(mx);
2163 csingle->parent = parent;
2164 csingle->next = NULL;
2165 csingle->name = "expand";
2166 csingle->type = MOD_XLAT;
2167 csingle->method = component;
2169 memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2170 sizeof(csingle->actions));
2172 mx->xlat_name = strdup(fmt);
2173 if (fmt[0] != '%') {
2177 strcpy(mx->xlat_name, fmt + 1);
2178 p = strrchr(mx->xlat_name, '`');
2186 * redundant, etc. can refer to modules or groups, but not much else.
2188 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
2192 for (ci=cf_item_find_next(cs, NULL);
2194 ci=cf_item_find_next(cs, ci)) {
2196 * If we're a redundant, etc. group, then the
2197 * intention is to call modules, rather than
2198 * processing logic. These checks aren't
2199 * *strictly* necessary, but they keep the users
2200 * from doing crazy things.
2202 if (cf_item_is_section(ci)) {
2203 CONF_SECTION *subcs = cf_item_to_section(ci);
2204 char const *name1 = cf_section_name1(subcs);
2206 if ((strcmp(name1, "if") == 0) ||
2207 (strcmp(name1, "else") == 0) ||
2208 (strcmp(name1, "elsif") == 0) ||
2209 (strcmp(name1, "update") == 0) ||
2210 (strcmp(name1, "switch") == 0) ||
2211 (strcmp(name1, "case") == 0)) {
2212 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
2219 if (cf_item_is_pair(ci)) {
2220 CONF_PAIR *cp = cf_item_to_pair(ci);
2221 if (cf_pair_value(cp) != NULL) {
2223 "Entry with no value is invalid");
2234 * Compile one entry of a module call.
2236 static modcallable *do_compile_modsingle(modcallable *parent,
2237 rlm_components_t component, CONF_ITEM *ci,
2239 char const **modname)
2241 char const *modrefname, *p;
2243 modcallable *csingle;
2244 module_instance_t *this;
2245 CONF_SECTION *cs, *subcs, *modules;
2247 char const *realname;
2248 rlm_components_t method = component;
2250 if (cf_item_is_section(ci)) {
2253 cs = cf_item_to_section(ci);
2254 modrefname = cf_section_name1(cs);
2255 name2 = cf_section_name2(cs);
2256 if (!name2) name2 = "";
2259 * group{}, redundant{}, or append{} may appear
2260 * where a single module instance was expected.
2261 * In that case, we hand it off to
2264 if (strcmp(modrefname, "group") == 0) {
2266 return do_compile_modgroup(parent, component, cs,
2268 grouptype, MOD_GROUP);
2270 } else if (strcmp(modrefname, "redundant") == 0) {
2273 if (!all_children_are_modules(cs, modrefname)) {
2277 return do_compile_modgroup(parent, component, cs,
2278 GROUPTYPE_REDUNDANT,
2279 grouptype, MOD_GROUP);
2281 } else if (strcmp(modrefname, "append") == 0) {
2283 return do_compile_modgroup(parent, component, cs,
2285 grouptype, MOD_GROUP);
2287 } else if (strcmp(modrefname, "load-balance") == 0) {
2290 if (!all_children_are_modules(cs, modrefname)) {
2294 return do_compile_modgroup(parent, component, cs,
2296 grouptype, MOD_LOAD_BALANCE);
2298 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
2301 if (!all_children_are_modules(cs, modrefname)) {
2305 return do_compile_modgroup(parent, component, cs,
2306 GROUPTYPE_REDUNDANT,
2307 grouptype, MOD_REDUNDANT_LOAD_BALANCE);
2310 } else if (strcmp(modrefname, "if") == 0) {
2311 if (!cf_section_name2(cs)) {
2312 cf_log_err(ci, "'if' without condition");
2317 csingle= do_compile_modgroup(parent, component, cs,
2320 if (!csingle) return NULL;
2325 } else if (strcmp(modrefname, "elsif") == 0) {
2327 ((parent->type == MOD_LOAD_BALANCE) ||
2328 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2329 cf_log_err(ci, "'elsif' cannot be used in this section");
2333 if (!cf_section_name2(cs)) {
2334 cf_log_err(ci, "'elsif' without condition");
2339 return do_compile_modgroup(parent, component, cs,
2341 grouptype, MOD_ELSIF);
2343 } else if (strcmp(modrefname, "else") == 0) {
2345 ((parent->type == MOD_LOAD_BALANCE) ||
2346 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2347 cf_log_err(ci, "'else' cannot be used in this section section");
2351 if (cf_section_name2(cs)) {
2352 cf_log_err(ci, "Cannot have conditions on 'else'");
2357 return do_compile_modgroup(parent, component, cs,
2359 grouptype, MOD_ELSE);
2361 } else if (strcmp(modrefname, "update") == 0) {
2364 return do_compile_modupdate(parent, component, cs,
2367 } else if (strcmp(modrefname, "switch") == 0) {
2370 return do_compile_modswitch (parent, component, cs);
2372 } else if (strcmp(modrefname, "case") == 0) {
2375 return do_compile_modcase(parent, component, cs);
2377 } else if (strcmp(modrefname, "foreach") == 0) {
2380 return do_compile_modforeach(parent, component, cs);
2383 } /* else it's something like sql { fail = 1 ...} */
2385 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2389 * Else it's a module reference, with updated return
2393 CONF_PAIR *cp = cf_item_to_pair(ci);
2394 modrefname = cf_pair_attr(cp);
2397 * Actions (ok = 1), etc. are orthogonal to just
2398 * about everything else.
2400 if (cf_pair_value(cp) != NULL) {
2401 cf_log_err(ci, "Entry is not a reference to a module");
2406 * In-place xlat's via %{...}.
2408 * This should really be removed from the server.
2410 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2411 (modrefname[0] == '`')) {
2412 return do_compile_modxlat(parent, component,
2419 * These can't be over-ridden.
2421 if (strcmp(modrefname, "break") == 0) {
2422 if (!cf_item_is_pair(ci)) {
2423 cf_log_err(ci, "Invalid use of 'break' as section name.");
2427 return do_compile_modbreak(parent, component, ci);
2430 if (strcmp(modrefname, "return") == 0) {
2431 if (!cf_item_is_pair(ci)) {
2432 cf_log_err(ci, "Invalid use of 'return' as section name.");
2436 return do_compile_modgroup(parent, component, NULL,
2437 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2443 * Run a virtual server. This is really terrible and
2444 * should be deleted.
2446 if (strncmp(modrefname, "server[", 7) == 0) {
2449 if (!cf_item_is_pair(ci)) {
2450 cf_log_err(ci, "Invalid syntax");
2454 strlcpy(buffer, modrefname + 7, sizeof(buffer));
2455 p = strrchr(buffer, ']');
2456 if (!p || p[1] != '\0' || (p == buffer)) {
2457 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2461 buffer[p - buffer] = '\0';
2463 cs = cf_section_sub_find_name2(NULL, "server", buffer);
2465 cf_log_err(ci, "No such server \"%s\".", buffer);
2470 * Ignore stupid attempts to over-ride the return
2473 return do_compile_modserver(parent, component, ci,
2474 modrefname, cs, buffer);
2478 * We now have a name. It can be one of two forms. A
2479 * bare module name, or a section named for the module,
2480 * with over-rides for the return codes.
2482 * The name can refer to a real module, in the "modules"
2483 * section. In that case, the name will be either the
2484 * first or second name of the sub-section of "modules".
2486 * Or, the name can refer to a policy, in the "policy"
2487 * section. In that case, the name will be first name of
2488 * the sub-section of "policy". Unless it's a "redudant"
2491 * Or, the name can refer to a "module.method", in which
2492 * case we're calling a different method than normal for
2495 * Or, the name can refer to a virtual module, in the
2496 * "instantiate" section. In that case, the name will be
2497 * the first of the sub-section of "instantiate". Unless
2498 * it's a "redudant" block...
2500 * We try these in sequence, from the bottom up. This is
2501 * so that things in "instantiate" and "policy" can
2502 * over-ride calls to real modules.
2509 * instantiate { ... name { ...} ... }
2510 * instantiate { ... name.method { ...} ... }
2511 * policy { ... name { .. } .. }
2512 * policy { ... name.method { .. } .. }
2514 * The "instantiate" virtual modules are identical to the
2515 * policies at this point. We should probably get rid of
2516 * the "instantiate" ones, as they're duplicate and
2520 cs = cf_section_find("instantiate");
2521 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
2524 (cs = cf_section_find("policy")) != NULL) {
2527 snprintf(buffer, sizeof(buffer), "%s.%s",
2528 modrefname, comp2str[component]);
2531 * Prefer name.section, then name.
2533 subcs = cf_section_sub_find_name2(cs, NULL,
2536 subcs = cf_section_sub_find_name2(cs, NULL,
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 if (cf_section_sub_find_name2(modules, NULL, realname)) {
2630 this = find_module_instance(modules, realname, true);
2631 if (this) goto allocate_csingle;
2636 if (realname != modrefname) {
2642 * We were asked to MAYBE load it and it
2643 * doesn't exist. Return a soft error.
2645 if (realname != modrefname) {
2646 *modname = modrefname;
2653 * No module found by that name. Maybe we're calling
2656 p = strrchr(modrefname, '.');
2662 * Find the component.
2664 for (i = RLM_COMPONENT_AUTH;
2665 i < RLM_COMPONENT_COUNT;
2667 if (strcmp(p, comp2str[i]) == 0) {
2670 strlcpy(buffer, modrefname, sizeof(buffer));
2671 buffer[p - modrefname - 1] = '\0';
2674 this = find_module_instance(modules, buffer, true);
2677 goto allocate_csingle;
2683 * FIXME: check for "module", and give error "no
2684 * such component" when we don't find the method.
2689 * Can't de-reference it to anything. Ugh.
2692 cf_log_err(ci, "Failed to find \"%s\" as a module or policy.", modrefname);
2693 cf_log_err(ci, "Please verify that the configuration exists in %s/mods-enabled/%s.", get_radius_dir(), modrefname);
2697 * We know it's all OK, allocate the structures, and fill
2702 * Check if the module in question has the necessary
2705 if (!this->entry->module->methods[method]) {
2706 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2711 single = talloc_zero(parent, modsingle);
2712 single->modinst = this;
2713 *modname = this->entry->module->name;
2715 csingle = mod_singletocallable(single);
2716 csingle->parent = parent;
2717 csingle->next = NULL;
2718 if (!parent || (component != RLM_COMPONENT_AUTH)) {
2719 memcpy(csingle->actions, defaultactions[component][grouptype],
2720 sizeof csingle->actions);
2721 } else { /* inside Auth-Type has different rules */
2722 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2723 sizeof csingle->actions);
2725 rad_assert(modrefname != NULL);
2726 csingle->name = realname;
2727 csingle->type = MOD_SINGLE;
2728 csingle->method = method;
2732 * Over-ride the default return codes of the module.
2734 if (cf_item_is_section(ci)) {
2737 cs = cf_item_to_section(ci);
2738 for (csi=cf_item_find_next(cs, NULL);
2740 csi=cf_item_find_next(cs, csi)) {
2742 if (cf_item_is_section(csi)) {
2743 cf_log_err(csi, "Subsection of module instance call not allowed");
2744 talloc_free(csingle);
2748 if (!cf_item_is_pair(csi)) continue;
2750 if (!compile_action(csingle, cf_item_to_pair(csi))) {
2751 talloc_free(csingle);
2760 modcallable *compile_modsingle(TALLOC_CTX *ctx,
2761 modcallable **parent,
2762 rlm_components_t component, CONF_ITEM *ci,
2763 char const **modname)
2770 CONF_SECTION *parentcs;
2772 g = talloc_zero(ctx, modgroup);
2773 memset(g, 0, sizeof(*g));
2774 g->grouptype = GROUPTYPE_SIMPLE;
2775 c = mod_grouptocallable(g);
2778 defaultactions[component][GROUPTYPE_SIMPLE],
2779 sizeof(c->actions));
2781 parentcs = cf_item_parent(ci);
2782 c->name = cf_section_name2(parentcs);
2784 c->name = cf_section_name1(parentcs);
2787 c->type = MOD_GROUP;
2788 c->method = component;
2791 *parent = mod_grouptocallable(g);
2794 ret = do_compile_modsingle(*parent, component, ci,
2797 dump_tree(component, ret);
2803 * Internal compile group code.
2805 static modcallable *do_compile_modgroup(modcallable *parent,
2806 rlm_components_t component, CONF_SECTION *cs,
2807 int grouptype, int parentgrouptype, int mod_type)
2814 g = talloc_zero(parent, modgroup);
2815 g->grouptype = grouptype;
2819 c = mod_grouptocallable(g);
2823 memset(c->actions, 0, sizeof(c->actions));
2825 if (!cs) { /* only for "break" and "return" */
2831 * Remember the name for printing, etc.
2833 * FIXME: We may also want to put the names into a
2834 * rbtree, so that groups can reference each other...
2836 c->name = cf_section_name2(cs);
2838 c->name = cf_section_name1(cs);
2839 if ((strcmp(c->name, "group") == 0) ||
2840 (strcmp(c->name, "redundant") == 0)) {
2842 } else if (c->type == MOD_GROUP) {
2843 c->type = MOD_POLICY;
2849 * Do load-time optimizations
2851 if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
2854 rad_assert(parent != NULL);
2856 if (c->type == MOD_IF) {
2857 g->cond = cf_data_find(g->cs, "if");
2858 rad_assert(g->cond != NULL);
2861 if (g->cond->type == COND_TYPE_FALSE) {
2862 INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
2863 unlang_keyword[g->mc.type],
2864 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2868 } else if (c->type == MOD_ELSIF) {
2870 g->cond = cf_data_find(g->cs, "if");
2871 rad_assert(g->cond != NULL);
2873 rad_assert(parent != NULL);
2874 p = mod_callabletogroup(parent);
2876 rad_assert(p->tail != NULL);
2878 f = mod_callabletogroup(p->tail);
2879 rad_assert((f->mc.type == MOD_IF) ||
2880 (f->mc.type == MOD_ELSIF));
2883 * If we took the previous condition, we
2884 * don't need to take this one.
2886 * We reset our condition to 'true', so
2887 * that subsequent sections can check
2888 * that they don't need to be executed.
2890 if (f->cond->type == COND_TYPE_TRUE) {
2892 INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
2893 unlang_keyword[g->mc.type],
2894 unlang_keyword[f->mc.type],
2895 cf_section_filename(g->cs), cf_section_lineno(g->cs));
2902 rad_assert(c->type == MOD_ELSE);
2904 rad_assert(parent != NULL);
2905 p = mod_callabletogroup(parent);
2907 rad_assert(p->tail != NULL);
2909 f = mod_callabletogroup(p->tail);
2910 rad_assert((f->mc.type == MOD_IF) ||
2911 (f->mc.type == MOD_ELSIF));
2914 * If we took the previous condition, we
2915 * don't need to take this one.
2917 if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
2921 * Else we need to compile this section
2927 * Loop over the children of this group.
2929 for (ci=cf_item_find_next(cs, NULL);
2931 ci=cf_item_find_next(cs, ci)) {
2934 * Sections are references to other groups, or
2935 * to modules with updated return codes.
2937 if (cf_item_is_section(ci)) {
2938 char const *junk = NULL;
2939 modcallable *single;
2940 CONF_SECTION *subcs = cf_item_to_section(ci);
2942 single = do_compile_modsingle(c, component, ci,
2945 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2946 cf_section_name1(subcs));
2950 add_child(g, single);
2952 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2956 char const *attr, *value;
2957 CONF_PAIR *cp = cf_item_to_pair(ci);
2959 attr = cf_pair_attr(cp);
2960 value = cf_pair_value(cp);
2963 * A CONF_PAIR is either a module
2964 * instance with no actions
2968 modcallable *single;
2969 char const *junk = NULL;
2971 single = do_compile_modsingle(c,
2977 if (cf_item_is_pair(ci) &&
2978 cf_pair_attr(cf_item_to_pair(ci))[0] == '-') {
2983 "Failed to parse \"%s\" entry.",
2988 add_child(g, single);
2991 * Or a module instance with action.
2993 } else if (!compile_action(c, cp)) {
2996 } /* else it worked */
3002 * Set the default actions, if they haven't already been
3005 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
3006 if (!c->actions[i]) {
3007 if (!parent || (component != RLM_COMPONENT_AUTH)) {
3008 c->actions[i] = defaultactions[component][parentgrouptype][i];
3009 } else { /* inside Auth-Type has different rules */
3010 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
3020 if (grouptype != GROUPTYPE_REDUNDANT) break;
3023 case MOD_LOAD_BALANCE:
3024 case MOD_REDUNDANT_LOAD_BALANCE:
3026 cf_log_err_cs(g->cs, "%s sections cannot be empty",
3027 cf_section_name1(g->cs));
3034 * FIXME: If there are no children, return NULL?
3036 return mod_grouptocallable(g);
3039 modcallable *compile_modgroup(modcallable *parent,
3040 rlm_components_t component, CONF_SECTION *cs)
3042 modcallable *ret = do_compile_modgroup(parent, component, cs,
3044 GROUPTYPE_SIMPLE, MOD_GROUP);
3046 if (debug_flag > 3) {
3047 modcall_debug(ret, 2);
3053 void add_to_modcallable(modcallable *parent, modcallable *this)
3057 rad_assert(this != NULL);
3058 rad_assert(parent != NULL);
3060 g = mod_callabletogroup(parent);
3067 static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t **pvpt, bool convert,
3068 DICT_ATTR const *da)
3074 value_pair_tmpl_t *vpt;
3078 rad_assert(vpt->type == TMPL_TYPE_XLAT);
3080 fmt = talloc_typed_strdup(vpt, vpt->name);
3081 slen = xlat_tokenize(vpt, fmt, &head, &error);
3084 char *spaces, *text;
3086 fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
3088 cf_log_err(ci, "Failed parsing expanded string:");
3089 cf_log_err(ci, "%s", text);
3090 cf_log_err(ci, "%s^ %s", spaces, error);
3092 talloc_free(spaces);
3098 * Convert %{Attribute-Name} to &Attribute-Name
3101 value_pair_tmpl_t *attr;
3103 attr = xlat_to_tmpl_attr(talloc_parent(vpt), head);
3106 * If it's a virtual attribute, leave it
3109 if (attr->tmpl_da->flags.virtual) {
3115 * If the attribute is of incompatible
3116 * type, leave it alone.
3118 if (da && (da->type != attr->tmpl_da->type)) {
3123 if (cf_item_is_pair(ci)) {
3124 CONF_PAIR *cp = cf_item_to_pair(ci);
3126 WARN("%s[%d] Please change %%{%s} to &%s",
3127 cf_pair_filename(cp), cf_pair_lineno(cp),
3128 attr->name, attr->name);
3130 CONF_SECTION *cs = cf_item_to_section(ci);
3132 WARN("%s[%d] Please change %%{%s} to &%s",
3133 cf_section_filename(cs), cf_section_lineno(cs),
3134 attr->name, attr->name);
3143 * Re-write it to be a pre-parsed XLAT structure.
3145 vpt->type = TMPL_TYPE_XLAT_STRUCT;
3146 vpt->tmpl_xlat = head;
3153 static bool pass2_regex_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
3158 rad_assert(vpt->type == TMPL_TYPE_REGEX);
3161 * It's a dynamic expansion. We can't expand the string,
3162 * but we can pre-parse it as an xlat struct. In that
3163 * case, we convert it to a pre-compiled XLAT.
3165 * This is a little more complicated than it needs to be
3166 * because radius_evaluate_map() keys off of the src
3167 * template type, instead of the operators. And, the
3168 * pass2_xlat_compile() function expects to get passed an
3169 * XLAT instead of a REGEX.
3171 if (strchr(vpt->name, '%')) {
3172 vpt->type = TMPL_TYPE_XLAT;
3173 return pass2_xlat_compile(ci, &vpt, false, NULL);
3176 slen = regex_compile(vpt, &preg, vpt->name, vpt->len,
3177 vpt->tmpl_iflag, vpt->tmpl_mflag, true, false);
3179 char *spaces, *text;
3181 fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
3183 cf_log_err(ci, "Invalid regular expression:");
3184 cf_log_err(ci, "%s", text);
3185 cf_log_err(ci, "%s^ %s", spaces, fr_strerror());
3187 talloc_free(spaces);
3193 vpt->type = TMPL_TYPE_REGEX_STRUCT;
3194 vpt->tmpl_preg = preg;
3200 static bool pass2_fixup_undefined(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
3202 DICT_ATTR const *da;
3204 rad_assert(vpt->type == TMPL_TYPE_ATTR_UNDEFINED);
3206 da = dict_attrbyname(vpt->tmpl_unknown_name);
3208 cf_log_err(ci, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
3213 vpt->type = TMPL_TYPE_ATTR;
3217 static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
3219 value_pair_map_t *map;
3221 if (c->type == COND_TYPE_EXISTS) {
3222 if (c->data.vpt->type == TMPL_TYPE_XLAT) {
3223 return pass2_xlat_compile(c->ci, &c->data.vpt, true, NULL);
3226 rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
3229 * The existence check might have been &Foo-Bar,
3230 * where Foo-Bar is defined by a module.
3232 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3233 if (!pass2_fixup_undefined(c->ci, c->data.vpt)) return false;
3234 c->pass2_fixup = PASS2_FIXUP_NONE;
3240 * Maps have a paircompare fixup applied to them.
3241 * Others get ignored.
3243 if (c->pass2_fixup == PASS2_FIXUP_NONE) {
3244 if (c->type == COND_TYPE_MAP) {
3252 map = c->data.map; /* shorter */
3257 * Where "foo" is dynamically defined.
3259 if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
3260 if (!dict_valbyname(map->lhs->tmpl_da->attr,
3261 map->lhs->tmpl_da->vendor,
3263 cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
3264 map->lhs->tmpl_da->name,
3270 * These guys can't have a paircompare fixup applied.
3272 c->pass2_fixup = PASS2_FIXUP_NONE;
3276 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3277 if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3278 if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
3281 if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3282 if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
3285 c->pass2_fixup = PASS2_FIXUP_NONE;
3290 * Just in case someone adds a new fixup later.
3292 rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
3293 (c->pass2_fixup == PASS2_PAIRCOMPARE));
3298 if (map->lhs->type == TMPL_TYPE_XLAT) {
3300 * Don't compile the LHS to an attribute
3301 * reference for now. When we do that, we've got
3302 * to check the RHS for type-specific data, and
3303 * parse it to a TMPL_TYPE_DATA.
3305 if (!pass2_xlat_compile(map->ci, &map->lhs, false, NULL)) {
3310 if (map->rhs->type == TMPL_TYPE_XLAT) {
3312 * Convert the RHS to an attribute reference only
3313 * if the LHS is an attribute reference, AND is
3314 * of the same type as the RHS.
3316 * We can fix this when the code in evaluate.c
3317 * can handle strings on the LHS, and attributes
3318 * on the RHS. For now, the code in parser.c
3321 if (map->lhs->type == TMPL_TYPE_ATTR) {
3322 DICT_ATTR const *da = c->cast;
3324 if (!c->cast) da = map->lhs->tmpl_da;
3326 if (!pass2_xlat_compile(map->ci, &map->rhs, true, da)) {
3331 if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3338 * Convert bare refs to %{Foreach-Variable-N}
3340 if ((map->lhs->type == TMPL_TYPE_LITERAL) &&
3341 (strncmp(map->lhs->name, "Foreach-Variable-", 17) == 0)) {
3344 value_pair_tmpl_t *vpt;
3346 fmt = talloc_asprintf(map->lhs, "%%{%s}", map->lhs->name);
3347 slen = tmpl_afrom_str(map, &vpt, fmt, talloc_array_length(fmt) - 1,
3348 T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
3350 char *spaces, *text;
3352 fr_canonicalize_error(map->ci, &spaces, &text, slen, fr_strerror());
3354 cf_log_err(map->ci, "Failed converting %s to xlat", map->lhs->name);
3355 cf_log_err(map->ci, "%s", fmt);
3356 cf_log_err(map->ci, "%s^ %s", spaces, text);
3358 talloc_free(spaces);
3364 talloc_free(map->lhs);
3369 if (map->rhs->type == TMPL_TYPE_REGEX) {
3370 if (!pass2_regex_compile(map->ci, map->rhs)) {
3374 rad_assert(map->lhs->type != TMPL_TYPE_REGEX);
3378 * Only attributes can have a paircompare registered, and
3379 * they can only be with the current REQUEST, and only
3380 * with the request pairs.
3382 if ((map->lhs->type != TMPL_TYPE_ATTR) ||
3383 (map->lhs->tmpl_request != REQUEST_CURRENT) ||
3384 (map->lhs->tmpl_list != PAIR_LIST_REQUEST)) {
3388 if (!radius_find_compare(map->lhs->tmpl_da)) return true;
3390 if (map->rhs->type == TMPL_TYPE_ATTR) {
3391 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
3396 if (map->rhs->type == TMPL_TYPE_REGEX) {
3397 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
3403 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
3408 if (map->op != T_OP_CMP_EQ) {
3409 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
3415 * Mark it as requiring a paircompare() call, instead of
3418 c->pass2_fixup = PASS2_PAIRCOMPARE;
3425 * Compile the RHS of update sections to xlat_exp_t
3427 static bool modcall_pass2_update(modgroup *g)
3429 value_pair_map_t *map;
3431 for (map = g->map; map != NULL; map = map->next) {
3432 if (map->rhs->type == TMPL_TYPE_XLAT) {
3433 rad_assert(map->rhs->tmpl_xlat == NULL);
3436 * FIXME: compile to attribute && handle
3437 * the conversion in map_to_vp().
3439 if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3444 rad_assert(map->rhs->type != TMPL_TYPE_REGEX);
3447 * Deal with undefined attributes now.
3449 if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3450 if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
3453 if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3454 if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
3463 * Do a second-stage pass on compiling the modules.
3465 bool modcall_pass2(modcallable *mc)
3472 for (c = mc; c != NULL; c = c->next) {
3480 g = mod_callabletogroup(c);
3481 if (g->done_pass2) goto do_next;
3483 name2 = cf_section_name2(g->cs);
3485 c->debug_name = unlang_keyword[c->type];
3487 c->debug_name = talloc_asprintf(c, "update %s", name2);
3490 if (!modcall_pass2_update(g)) {
3493 g->done_pass2 = true;
3496 case MOD_XLAT: /* @todo: pre-parse xlat's */
3503 c->debug_name = c->name;
3504 break; /* do nothing */
3509 g = mod_callabletogroup(c);
3510 if (g->done_pass2) goto do_next;
3512 name2 = cf_section_name2(g->cs);
3513 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3516 * The compilation code takes care of
3517 * simplifying 'true' and 'false'
3518 * conditions. For others, we have to do
3519 * a second pass to parse && compile
3522 if (!((g->cond->type == COND_TYPE_TRUE) ||
3523 (g->cond->type == COND_TYPE_FALSE))) {
3524 if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
3529 if (!modcall_pass2(g->children)) return false;
3530 g->done_pass2 = true;
3536 g = mod_callabletogroup(c);
3537 if (g->done_pass2) goto do_next;
3539 name2 = cf_section_name2(g->cs);
3540 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3543 * We had &Foo-Bar, where Foo-Bar is
3544 * defined by a module.
3547 rad_assert(c->name != NULL);
3548 rad_assert(c->name[0] == '&');
3549 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3551 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3552 cf_section_name2_type(g->cs),
3553 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3555 char *spaces, *text;
3558 fr_canonicalize_error(g->cs, &spaces, &text, slen, fr_strerror());
3560 cf_log_err_cs(g->cs, "Syntax error");
3561 cf_log_err_cs(g->cs, "%s", c->name);
3562 cf_log_err_cs(g->cs, "%s^ %s", spaces, text);
3564 talloc_free(spaces);
3574 * Statically compile xlats
3576 if (g->vpt->type == TMPL_TYPE_XLAT) {
3577 if (!pass2_xlat_compile(cf_section_to_item(g->cs),
3578 &g->vpt, true, NULL)) {
3586 * We may have: switch Foo-Bar {
3588 * where Foo-Bar is an attribute defined
3589 * by a module. Since there's no leading
3590 * &, it's parsed as a literal. But if
3591 * we can parse it as an attribute,
3592 * switch to using that.
3594 if (g->vpt->type == TMPL_TYPE_LITERAL) {
3595 value_pair_tmpl_t *vpt;
3597 slen = tmpl_afrom_str(g->cs, &vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3598 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3599 if (slen < 0) goto parse_error;
3600 if (vpt->type == TMPL_TYPE_ATTR) {
3601 talloc_free(g->vpt);
3609 * Warn about old-style configuration.
3611 * DEPRECATED: switch User-Name { ...
3612 * ALLOWED : switch &User-Name { ...
3614 if ((g->vpt->type == TMPL_TYPE_ATTR) &&
3615 (c->name[0] != '&')) {
3616 WARN("%s[%d]: Please change %s to &%s",
3617 cf_section_filename(g->cs),
3618 cf_section_lineno(g->cs),
3623 if (!modcall_pass2(g->children)) return false;
3624 g->done_pass2 = true;
3628 g = mod_callabletogroup(c);
3629 if (g->done_pass2) goto do_next;
3631 name2 = cf_section_name2(g->cs);
3633 c->debug_name = unlang_keyword[c->type];
3635 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3638 rad_assert(c->parent != NULL);
3639 rad_assert(c->parent->type == MOD_SWITCH);
3642 * The statement may refer to an
3643 * attribute which doesn't exist until
3644 * all of the modules have been loaded.
3645 * Check for that now.
3647 if (!g->vpt && c->name &&
3648 (c->name[0] == '&') &&
3649 (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
3650 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3651 cf_section_name2_type(g->cs),
3652 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3653 if (slen < 0) goto parse_error;
3657 * We have "case {...}". There's no
3658 * argument, so we don't need to check
3661 if (!g->vpt) goto do_children;
3664 * Do type-specific checks on the case statement
3666 if (g->vpt->type == TMPL_TYPE_LITERAL) {
3669 f = mod_callabletogroup(mc->parent);
3670 rad_assert(f->vpt != NULL);
3673 * We're switching over an
3674 * attribute. Check that the
3677 if (f->vpt->type == TMPL_TYPE_ATTR) {
3678 rad_assert(f->vpt->tmpl_da != NULL);
3680 if (!tmpl_cast_in_place(g->vpt, f->vpt->tmpl_da->type, f->vpt->tmpl_da)) {
3681 cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
3691 * Compile and sanity check xlat
3694 if (g->vpt->type == TMPL_TYPE_XLAT) {
3697 f = mod_callabletogroup(mc->parent);
3698 rad_assert(f->vpt != NULL);
3701 * Don't expand xlat's into an
3702 * attribute of a different type.
3704 if (f->vpt->type == TMPL_TYPE_ATTR) {
3705 if (!pass2_xlat_compile(cf_section_to_item(g->cs),
3706 &g->vpt, true, f->vpt->tmpl_da)) {
3710 if (!pass2_xlat_compile(cf_section_to_item(g->cs),
3711 &g->vpt, true, NULL)) {
3717 if (!modcall_pass2(g->children)) return false;
3718 g->done_pass2 = true;
3722 g = mod_callabletogroup(c);
3723 if (g->done_pass2) goto do_next;
3725 name2 = cf_section_name2(g->cs);
3726 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
3729 * Already parsed, handle the children.
3731 if (g->vpt) goto check_children;
3734 * We had &Foo-Bar, where Foo-Bar is
3735 * defined by a module.
3737 rad_assert(c->name != NULL);
3738 rad_assert(c->name[0] == '&');
3739 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3742 * The statement may refer to an
3743 * attribute which doesn't exist until
3744 * all of the modules have been loaded.
3745 * Check for that now.
3747 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3748 REQUEST_CURRENT, PAIR_LIST_REQUEST);
3749 if (slen < 0) goto parse_error;
3752 rad_assert((g->vpt->type == TMPL_TYPE_ATTR) || (g->vpt->type == TMPL_TYPE_LIST));
3753 if (g->vpt->tmpl_num != NUM_ALL) {
3754 cf_log_err_cs(g->cs, "MUST NOT use instance selectors in 'foreach'");
3757 if (!modcall_pass2(g->children)) return false;
3758 g->done_pass2 = true;
3762 c->debug_name = unlang_keyword[c->type];
3766 g = mod_callabletogroup(c);
3767 c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], cf_section_name1(g->cs));
3772 case MOD_LOAD_BALANCE:
3773 case MOD_REDUNDANT_LOAD_BALANCE:
3774 c->debug_name = unlang_keyword[c->type];
3779 g = mod_callabletogroup(c);
3781 c->debug_name = mc->name; /* for authorize, etc. */
3783 } else if (c->type == MOD_GROUP) { /* for Auth-Type, etc. */
3784 char const *name1 = cf_section_name1(g->cs);
3786 if (strcmp(name1, unlang_keyword[c->type]) != 0) {
3787 c->debug_name = talloc_asprintf(c, "%s %s", name1, cf_section_name2(g->cs));
3791 if (g->done_pass2) goto do_next;
3792 if (!modcall_pass2(g->children)) return false;
3793 g->done_pass2 = true;
3798 rad_assert(c->debug_name != NULL);
3804 void modcall_debug(modcallable *mc, int depth)
3808 value_pair_map_t *map;
3811 for (this = mc; this != NULL; this = this->next) {
3812 switch (this->type) {
3817 modsingle *single = mod_callabletosingle(this);
3819 DEBUG("%.*s%s", depth, modcall_spaces,
3820 single->modinst->name);
3826 g = mod_callabletogroup(this);
3827 DEBUG("%.*s%s {", depth, modcall_spaces,
3828 unlang_keyword[this->type]);
3830 for (map = g->map; map != NULL; map = map->next) {
3831 map_prints(buffer, sizeof(buffer), map);
3832 DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
3835 DEBUG("%.*s}", depth, modcall_spaces);
3839 g = mod_callabletogroup(this);
3840 DEBUG("%.*s%s {", depth, modcall_spaces,
3841 unlang_keyword[this->type]);
3842 modcall_debug(g->children, depth + 1);
3843 DEBUG("%.*s}", depth, modcall_spaces);
3848 g = mod_callabletogroup(this);
3849 fr_cond_sprint(buffer, sizeof(buffer), g->cond);
3850 DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
3851 unlang_keyword[this->type], buffer);
3852 modcall_debug(g->children, depth + 1);
3853 DEBUG("%.*s}", depth, modcall_spaces);
3858 g = mod_callabletogroup(this);
3859 tmpl_prints(buffer, sizeof(buffer), g->vpt, NULL);
3860 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3861 unlang_keyword[this->type], buffer);
3862 modcall_debug(g->children, depth + 1);
3863 DEBUG("%.*s}", depth, modcall_spaces);
3868 g = mod_callabletogroup(this);
3869 DEBUG("%.*s%s %s {", depth, modcall_spaces,
3870 unlang_keyword[this->type], this->name);
3871 modcall_debug(g->children, depth + 1);
3872 DEBUG("%.*s}", depth, modcall_spaces);
3876 DEBUG("%.*sbreak", depth, modcall_spaces);
3881 g = mod_callabletogroup(this);
3882 DEBUG("%.*s%s {", depth, modcall_spaces,
3883 unlang_keyword[this->type]);
3884 modcall_debug(g->children, depth + 1);
3885 DEBUG("%.*s}", depth, modcall_spaces);
3889 case MOD_LOAD_BALANCE:
3890 case MOD_REDUNDANT_LOAD_BALANCE:
3891 g = mod_callabletogroup(this);
3892 DEBUG("%.*s%s {", depth, modcall_spaces,
3893 unlang_keyword[this->type]);
3894 modcall_debug(g->children, depth + 1);
3895 DEBUG("%.*s}", depth, modcall_spaces);