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
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modpriv.h>
28 #include <freeradius-devel/modcall.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 int, CONF_SECTION *, const char *,
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/README.failover */
49 struct modcallable *next;
52 int actions[RLM_MODULE_NUMCODES];
53 enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE, MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE } type;
56 #define GROUPTYPE_SIMPLE 0
57 #define GROUPTYPE_REDUNDANT 1
58 #define GROUPTYPE_APPEND 2
59 #define GROUPTYPE_COUNT 3
62 modcallable mc; /* self */
63 int grouptype; /* after mc */
64 modcallable *children;
71 module_instance_t *modinst;
74 static const LRAD_NAME_NUMBER grouptype_table[] = {
75 { "", GROUPTYPE_SIMPLE },
76 { "redundant ", GROUPTYPE_REDUNDANT },
77 { "append ", GROUPTYPE_APPEND },
81 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
82 * so we often want to go back and forth between them. */
83 static modsingle *mod_callabletosingle(modcallable *p)
85 rad_assert(p->type==MOD_SINGLE);
86 return (modsingle *)p;
88 static modgroup *mod_callabletogroup(modcallable *p)
90 rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_CASE));
94 static modcallable *mod_singletocallable(modsingle *p)
96 return (modcallable *)p;
98 static modcallable *mod_grouptocallable(modgroup *p)
100 return (modcallable *)p;
103 /* modgroups are grown by adding a modcallable to the end */
104 static void add_child(modgroup *g, modcallable *c)
106 modcallable **head = &g->children;
107 modcallable *node = *head;
108 modcallable **last = head;
117 rad_assert(c->next == NULL);
119 c->parent = mod_grouptocallable(g);
122 /* Here's where we recognize all of our keywords: first the rcodes, then the
124 static const LRAD_NAME_NUMBER rcode_table[] = {
125 { "reject", RLM_MODULE_REJECT },
126 { "fail", RLM_MODULE_FAIL },
127 { "ok", RLM_MODULE_OK },
128 { "handled", RLM_MODULE_HANDLED },
129 { "invalid", RLM_MODULE_INVALID },
130 { "userlock", RLM_MODULE_USERLOCK },
131 { "notfound", RLM_MODULE_NOTFOUND },
132 { "noop", RLM_MODULE_NOOP },
133 { "updated", RLM_MODULE_UPDATED },
139 * Compile action && rcode for later use.
141 static int compile_action(modcallable *c, const char *attr, const char *value,
142 const char *filename, int lineno)
146 if (!strcasecmp(value, "return"))
147 action = MOD_ACTION_RETURN;
149 else if (!strcasecmp(value, "reject"))
150 action = MOD_ACTION_REJECT;
152 else if (strspn(value, "0123456789")==strlen(value)) {
153 action = atoi(value);
156 * Don't allow priority zero, for future use.
158 if (action == 0) return 0;
161 "%s[%d]: Unknown action '%s'.\n",
162 filename, lineno, value);
166 if (strcasecmp(attr, "default") != 0) {
169 rcode = lrad_str2int(rcode_table, attr, -1);
172 "%s[%d]: Unknown module rcode '%s'.\n",
173 filename, lineno, attr);
176 c->actions[rcode] = action;
178 } else { /* set all unset values to the default */
181 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
182 if (!c->actions[i]) c->actions[i] = action;
189 /* Some short names for debugging output */
190 static const char * const comp2str[] = {
201 #ifdef HAVE_PTHREAD_H
203 * Lock the mutex for the module
205 static void safe_lock(module_instance_t *instance)
208 pthread_mutex_lock(instance->mutex);
212 * Unlock the mutex for the module
214 static void safe_unlock(module_instance_t *instance)
217 pthread_mutex_unlock(instance->mutex);
221 * No threads: these functions become NULL's.
223 #define safe_lock(foo)
224 #define safe_unlock(foo)
227 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
230 int myresult = default_result;
232 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
233 comp2str[component], sp->modinst->name,
234 sp->modinst->entry->name, request->number);
235 safe_lock(sp->modinst);
238 * For logging unresponsive children.
240 request->module = sp->modinst->name;
242 myresult = sp->modinst->entry->module->methods[component](
243 sp->modinst->insthandle, request);
245 request->module = "<server-core>";
246 safe_unlock(sp->modinst);
247 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
248 comp2str[component], sp->modinst->name,
249 sp->modinst->entry->name, request->number);
255 static int default_component_results[RLM_COMPONENT_COUNT] = {
256 RLM_MODULE_REJECT, /* AUTH */
257 RLM_MODULE_NOTFOUND, /* AUTZ */
258 RLM_MODULE_NOOP, /* PREACCT */
259 RLM_MODULE_NOOP, /* ACCT */
260 RLM_MODULE_FAIL, /* SESS */
261 RLM_MODULE_NOOP, /* PRE_PROXY */
262 RLM_MODULE_NOOP, /* POST_PROXY */
263 RLM_MODULE_NOOP /* POST_AUTH */
267 static const char *group_name[] = {
271 "load-balance group",
272 "redundant-load-balance group",
281 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
283 #define MODCALL_STACK_MAX (32)
286 * Don't call the modules recursively. Instead, do them
287 * iteratively, and manage the call stack ourselves.
289 typedef struct modcall_stack {
292 int priority[MODCALL_STACK_MAX];
293 int result[MODCALL_STACK_MAX];
294 modcallable *children[MODCALL_STACK_MAX];
295 modcallable *start[MODCALL_STACK_MAX];
300 * Call a module, iteratively, with a local stack, rather than
301 * recursively. What did Paul Graham say about Lisp...?
303 int modcall(int component, modcallable *c, REQUEST *request)
307 modcallable *parent, *child;
309 int if_taken, was_if;
313 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
314 return RLM_MODULE_FAIL;
318 return default_component_results[component];
321 stack.priority[0] = 0;
322 stack.children[0] = c;
323 myresult = stack.result[0] = default_component_results[component];
324 was_if = if_taken = FALSE;
328 * A module has taken too long to process the request,
329 * and we've been told to stop processing it.
331 if (request->master_state == REQUEST_STOP_PROCESSING) {
332 myresult = RLM_MODULE_FAIL;
336 child = stack.children[stack.pointer];
337 rad_assert(child != NULL);
338 parent = child->parent;
340 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
341 if (!was_if) { /* error */
342 DEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
343 stack.pointer + 1, modcall_spaces,
344 group_name[child->type],
349 DEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
350 stack.pointer + 1, modcall_spaces,
351 group_name[child->type],
358 * "if" or "elsif". Evaluate the condition.
360 if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {
361 int condition = TRUE;
362 const char *p = child->name;
364 DEBUG2("%.*s? %s %s",
365 stack.pointer + 1, modcall_spaces,
366 (child->type == MOD_IF) ? "if" : "elsif",
369 if (radius_evaluate_condition(request, 0, &p,
371 DEBUG2("%.*s? %s %s -> %s",
372 stack.pointer + 1, modcall_spaces,
373 (child->type == MOD_IF) ? "if" : "elsif",
374 child->name, (condition != FALSE) ? "TRUE" : "FALSE");
377 * This should never happen, the
378 * condition is checked when the
379 * module section is loaded.
385 stack.children[stack.pointer] = NULL;
389 } /* else process it as a simple group */
392 if (child->type == MOD_UPDATE) {
393 modgroup *g = mod_callabletogroup(child);
395 myresult = radius_update_attrlist(request, g->cs,
396 g->vps, child->name);
401 * Child is a group that has children of it's own.
403 if (child->type != MOD_SINGLE) {
406 modgroup *g = mod_callabletogroup(child);
411 * Catastrophic error. This SHOULD have
412 * been caught when we were reading in the
417 if (stack.pointer >= MODCALL_STACK_MAX) {
418 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
422 stack.priority[stack.pointer] = 0;
423 stack.result[stack.pointer] = default_component_results[component];
424 switch (child->type) {
432 stack.children[stack.pointer] = g->children;
436 * See the "camel book" for why
439 * If (rand(0..n) < 1), pick the
440 * current realm. We add a scale
441 * factor of 65536, to avoid
444 case MOD_LOAD_BALANCE:
445 case MOD_REDUNDANT_LOAD_BALANCE:
447 for(p = g->children; p; p = p->next) {
456 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
460 stack.children[stack.pointer] = q;
464 radius_xlat(buffer, sizeof(buffer),
465 child->name, request, NULL);
468 for(p = g->children; p; p = p->next) {
469 if (strcmp(buffer, p->name) == 0) {
474 stack.children[stack.pointer] = q;
478 DEBUG2("Internal sanity check failed in modcall %d", child->type);
479 exit(1); /* internal sanity check failure */
484 stack.start[stack.pointer] = stack.children[stack.pointer];
486 DEBUG2("%.*s- entering %s %s",
487 stack.pointer, modcall_spaces,
488 group_name[child->type], child->name);
491 * Catch the special case of a NULL group.
493 if (!stack.children[stack.pointer]) {
495 * Print message for NULL group
497 DEBUG2("%.*s- %s returns %s",
498 stack.pointer + 1, modcall_spaces,
500 lrad_int2str(rcode_table,
501 stack.result[stack.pointer],
507 * The child may be a group, so we want to
508 * recurse into it's children, rather than
509 * falling through to the code below.
515 * Process a stand-alone child, and fall through
516 * to dealing with it's parent.
518 sp = mod_callabletosingle(child);
520 myresult = call_modsingle(component, sp, request,
521 default_component_results[component]);
523 DEBUG2("%.*s[%s] returns %s",
524 stack.pointer + 1, modcall_spaces,
526 lrad_int2str(rcode_table, myresult, "??"));
530 * FIXME: Allow modules to push a modcallable
531 * onto this stack. This should simplify
532 * configuration a LOT!
534 * Once we do that, we can't do load-time
535 * checking of the maximum stack depth, and we've
536 * got to cache the stack pointer before storing
539 * Also, if the stack changed, we need to set
540 * children[ptr] to NULL, and process the next
541 * entry on the stack, rather than falling
542 * through to finalize the processing of this
545 * Don't put "myresult" on the stack here,
546 * we have to do so with priority.
550 * We roll back up the stack at this point.
554 * The child's action says return. Do so.
556 if (child->actions[myresult] == MOD_ACTION_RETURN) {
557 stack.result[stack.pointer] = myresult;
558 stack.children[stack.pointer] = NULL;
563 * If "reject", break out of the loop and return
566 if (child->actions[myresult] == MOD_ACTION_REJECT) {
567 stack.children[stack.pointer] = NULL;
568 stack.result[stack.pointer] = RLM_MODULE_REJECT;
573 * Otherwise, the action is a number, the
574 * preference level of this return code. If no
575 * higher preference has been seen yet, remember
578 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
579 stack.result[stack.pointer] = myresult;
580 stack.priority[stack.pointer] = child->actions[myresult];
584 * No parent, we must be done.
587 rad_assert(stack.pointer == 0);
588 myresult = stack.result[0];
592 rad_assert(child != NULL);
595 * Go to the "next" child, whatever that is.
597 switch (parent->type) {
603 stack.children[stack.pointer] = child->next;
607 case MOD_LOAD_BALANCE:
608 stack.children[stack.pointer] = NULL;
611 case MOD_REDUNDANT_LOAD_BALANCE:
613 stack.children[stack.pointer] = child->next;
615 modgroup *g = mod_callabletogroup(parent);
617 stack.children[stack.pointer] = g->children;
619 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
620 stack.children[stack.pointer] = NULL;
624 DEBUG2("Internal sanity check failed in modcall next %d", child->type);
629 * No child, we're done this group, and we return
630 * "myresult" to the caller by pushing it back up
633 if (!stack.children[stack.pointer]) {
635 rad_assert(stack.pointer > 0);
636 myresult = stack.result[stack.pointer];
639 if (stack.pointer == 0) break;
641 DEBUG2("%.*s- %s %s returns %s",
642 stack.pointer + 1, modcall_spaces,
643 group_name[parent->type], parent->name,
644 lrad_int2str(rcode_table, myresult, "??"));
646 if ((parent->type == MOD_IF) ||
647 (parent->type == MOD_ELSIF)) {
648 if_taken = was_if = TRUE;
650 if_taken = was_if = FALSE;
656 child = stack.children[stack.pointer];
657 parent = child->parent;
661 } /* loop until done */
668 static const char *action2str(int action)
671 if(action==MOD_ACTION_RETURN)
673 if(action==MOD_ACTION_REJECT)
675 snprintf(buf, sizeof buf, "%d", action);
679 /* If you suspect a bug in the parser, you'll want to use these dump
680 * functions. dump_tree should reproduce a whole tree exactly as it was found
681 * in radiusd.conf, but in long form (all actions explicitly defined) */
682 static void dump_mc(modcallable *c, int indent)
686 if(c->type==MOD_SINGLE) {
687 modsingle *single = mod_callabletosingle(c);
688 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
689 single->modinst->name);
691 modgroup *g = mod_callabletogroup(c);
693 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
694 group_name[c->type]);
695 for(p = g->children;p;p = p->next)
696 dump_mc(p, indent+1);
699 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
700 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
701 lrad_int2str(rcode_table, i, "??"),
702 action2str(c->actions[i]));
705 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
708 static void dump_tree(int comp, modcallable *c)
710 DEBUG("[%s]", comp2str[comp]);
714 #define dump_tree(a, b)
717 /* These are the default actions. For each component, the group{} block
718 * behaves like the code from the old module_*() function. redundant{} and
719 * append{} are based on my guesses of what they will be used for. --Pac. */
721 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
727 MOD_ACTION_RETURN, /* reject */
729 MOD_ACTION_RETURN, /* ok */
730 MOD_ACTION_RETURN, /* handled */
732 MOD_ACTION_RETURN, /* userlock */
733 MOD_ACTION_RETURN, /* notfound */
739 MOD_ACTION_RETURN, /* reject */
741 MOD_ACTION_RETURN, /* ok */
742 MOD_ACTION_RETURN, /* handled */
743 MOD_ACTION_RETURN, /* invalid */
744 MOD_ACTION_RETURN, /* userlock */
745 MOD_ACTION_RETURN, /* notfound */
746 MOD_ACTION_RETURN, /* noop */
747 MOD_ACTION_RETURN /* updated */
751 MOD_ACTION_RETURN, /* reject */
753 MOD_ACTION_RETURN, /* ok */
754 MOD_ACTION_RETURN, /* handled */
755 MOD_ACTION_RETURN, /* invalid */
756 MOD_ACTION_RETURN, /* userlock */
758 MOD_ACTION_RETURN, /* noop */
759 MOD_ACTION_RETURN /* updated */
766 MOD_ACTION_RETURN, /* reject */
767 MOD_ACTION_RETURN, /* fail */
769 MOD_ACTION_RETURN, /* handled */
770 MOD_ACTION_RETURN, /* invalid */
771 MOD_ACTION_RETURN, /* userlock */
778 MOD_ACTION_RETURN, /* reject */
780 MOD_ACTION_RETURN, /* ok */
781 MOD_ACTION_RETURN, /* handled */
782 MOD_ACTION_RETURN, /* invalid */
783 MOD_ACTION_RETURN, /* userlock */
784 MOD_ACTION_RETURN, /* notfound */
785 MOD_ACTION_RETURN, /* noop */
786 MOD_ACTION_RETURN /* updated */
790 MOD_ACTION_RETURN, /* reject */
792 MOD_ACTION_RETURN, /* ok */
793 MOD_ACTION_RETURN, /* handled */
794 MOD_ACTION_RETURN, /* invalid */
795 MOD_ACTION_RETURN, /* userlock */
797 MOD_ACTION_RETURN, /* noop */
798 MOD_ACTION_RETURN /* updated */
805 MOD_ACTION_RETURN, /* reject */
806 MOD_ACTION_RETURN, /* fail */
808 MOD_ACTION_RETURN, /* handled */
809 MOD_ACTION_RETURN, /* invalid */
810 MOD_ACTION_RETURN, /* userlock */
811 MOD_ACTION_RETURN, /* notfound */
817 MOD_ACTION_RETURN, /* reject */
819 MOD_ACTION_RETURN, /* ok */
820 MOD_ACTION_RETURN, /* handled */
821 MOD_ACTION_RETURN, /* invalid */
822 MOD_ACTION_RETURN, /* userlock */
823 MOD_ACTION_RETURN, /* notfound */
824 MOD_ACTION_RETURN, /* noop */
825 MOD_ACTION_RETURN /* updated */
829 MOD_ACTION_RETURN, /* reject */
831 MOD_ACTION_RETURN, /* ok */
832 MOD_ACTION_RETURN, /* handled */
833 MOD_ACTION_RETURN, /* invalid */
834 MOD_ACTION_RETURN, /* userlock */
836 MOD_ACTION_RETURN, /* noop */
837 MOD_ACTION_RETURN /* updated */
844 MOD_ACTION_RETURN, /* reject */
845 MOD_ACTION_RETURN, /* fail */
847 MOD_ACTION_RETURN, /* handled */
848 MOD_ACTION_RETURN, /* invalid */
849 MOD_ACTION_RETURN, /* userlock */
850 MOD_ACTION_RETURN, /* notfound */
858 MOD_ACTION_RETURN, /* ok */
859 MOD_ACTION_RETURN, /* handled */
868 MOD_ACTION_RETURN, /* reject */
870 MOD_ACTION_RETURN, /* ok */
871 MOD_ACTION_RETURN, /* handled */
872 MOD_ACTION_RETURN, /* invalid */
873 MOD_ACTION_RETURN, /* userlock */
875 MOD_ACTION_RETURN, /* noop */
876 MOD_ACTION_RETURN /* updated */
883 MOD_ACTION_RETURN, /* reject */
885 MOD_ACTION_RETURN, /* ok */
886 MOD_ACTION_RETURN, /* handled */
887 MOD_ACTION_RETURN, /* invalid */
888 MOD_ACTION_RETURN, /* userlock */
889 MOD_ACTION_RETURN, /* notfound */
890 MOD_ACTION_RETURN, /* noop */
891 MOD_ACTION_RETURN /* updated */
895 MOD_ACTION_RETURN, /* reject */
897 MOD_ACTION_RETURN, /* ok */
898 MOD_ACTION_RETURN, /* handled */
899 MOD_ACTION_RETURN, /* invalid */
900 MOD_ACTION_RETURN, /* userlock */
901 MOD_ACTION_RETURN, /* notfound */
902 MOD_ACTION_RETURN, /* noop */
903 MOD_ACTION_RETURN /* updated */
907 MOD_ACTION_RETURN, /* reject */
909 MOD_ACTION_RETURN, /* ok */
910 MOD_ACTION_RETURN, /* handled */
911 MOD_ACTION_RETURN, /* invalid */
912 MOD_ACTION_RETURN, /* userlock */
913 MOD_ACTION_RETURN, /* notfound */
914 MOD_ACTION_RETURN, /* noop */
915 MOD_ACTION_RETURN /* updated */
922 MOD_ACTION_RETURN, /* reject */
923 MOD_ACTION_RETURN, /* fail */
925 MOD_ACTION_RETURN, /* handled */
926 MOD_ACTION_RETURN, /* invalid */
927 MOD_ACTION_RETURN, /* userlock */
934 MOD_ACTION_RETURN, /* reject */
936 MOD_ACTION_RETURN, /* ok */
937 MOD_ACTION_RETURN, /* handled */
938 MOD_ACTION_RETURN, /* invalid */
939 MOD_ACTION_RETURN, /* userlock */
940 MOD_ACTION_RETURN, /* notfound */
941 MOD_ACTION_RETURN, /* noop */
942 MOD_ACTION_RETURN /* updated */
946 MOD_ACTION_RETURN, /* reject */
948 MOD_ACTION_RETURN, /* ok */
949 MOD_ACTION_RETURN, /* handled */
950 MOD_ACTION_RETURN, /* invalid */
951 MOD_ACTION_RETURN, /* userlock */
953 MOD_ACTION_RETURN, /* noop */
954 MOD_ACTION_RETURN /* updated */
961 MOD_ACTION_RETURN, /* reject */
962 MOD_ACTION_RETURN, /* fail */
964 MOD_ACTION_RETURN, /* handled */
965 MOD_ACTION_RETURN, /* invalid */
966 MOD_ACTION_RETURN, /* userlock */
973 MOD_ACTION_RETURN, /* reject */
975 MOD_ACTION_RETURN, /* ok */
976 MOD_ACTION_RETURN, /* handled */
977 MOD_ACTION_RETURN, /* invalid */
978 MOD_ACTION_RETURN, /* userlock */
979 MOD_ACTION_RETURN, /* notfound */
980 MOD_ACTION_RETURN, /* noop */
981 MOD_ACTION_RETURN /* updated */
985 MOD_ACTION_RETURN, /* reject */
987 MOD_ACTION_RETURN, /* ok */
988 MOD_ACTION_RETURN, /* handled */
989 MOD_ACTION_RETURN, /* invalid */
990 MOD_ACTION_RETURN, /* userlock */
992 MOD_ACTION_RETURN, /* noop */
993 MOD_ACTION_RETURN /* updated */
1000 MOD_ACTION_RETURN, /* reject */
1001 MOD_ACTION_RETURN, /* fail */
1003 MOD_ACTION_RETURN, /* handled */
1004 MOD_ACTION_RETURN, /* invalid */
1005 MOD_ACTION_RETURN, /* userlock */
1012 MOD_ACTION_RETURN, /* reject */
1014 MOD_ACTION_RETURN, /* ok */
1015 MOD_ACTION_RETURN, /* handled */
1016 MOD_ACTION_RETURN, /* invalid */
1017 MOD_ACTION_RETURN, /* userlock */
1018 MOD_ACTION_RETURN, /* notfound */
1019 MOD_ACTION_RETURN, /* noop */
1020 MOD_ACTION_RETURN /* updated */
1024 MOD_ACTION_RETURN, /* reject */
1026 MOD_ACTION_RETURN, /* ok */
1027 MOD_ACTION_RETURN, /* handled */
1028 MOD_ACTION_RETURN, /* invalid */
1029 MOD_ACTION_RETURN, /* userlock */
1031 MOD_ACTION_RETURN, /* noop */
1032 MOD_ACTION_RETURN /* updated */
1038 static modcallable *do_compile_modupdate(modcallable *parent,
1039 int component, CONF_SECTION *cs,
1040 const char *filename, int lineno,
1045 modcallable *csingle;
1047 VALUE_PAIR *head, **tail;
1049 static const char *attrlist_names[] = {
1050 "request", "reply", "proxy-request", "proxy-reply",
1051 "config", "control", NULL
1054 component = component; /* -Wunused */
1056 if (!cf_section_name2(cs)) {
1057 radlog(L_ERR|L_CONS,
1058 "%s[%d] Require list name for 'update'.\n",
1063 for (i = 0; attrlist_names[i] != NULL; i++) {
1064 if (strcmp(name2, attrlist_names[i]) == 0) {
1071 radlog(L_ERR, "%s[%d]: Unknown attribute list \"%s\"",
1072 filename, lineno, name2);
1080 * Walk through the children of the update section,
1081 * ensuring that they're all known attributes.
1083 for (ci=cf_item_find_next(cs, NULL);
1085 ci=cf_item_find_next(cs, ci)) {
1089 if (cf_item_is_section(ci)) {
1090 radlog(L_ERR|L_CONS,
1091 "%s[%d]: \"update\" sections cannot have subsections",
1093 cf_section_lineno(cf_itemtosection(ci)));
1097 cp = cf_itemtopair(ci); /* can't return NULL */
1098 vp = cf_pairtovp(cp);
1101 radlog(L_ERR|L_CONS, "%s[%d]: ERROR: %s",
1102 filename, cf_pair_lineno(cp), librad_errstr);
1106 if ((vp->operator != T_OP_EQ) &&
1107 (vp->operator != T_OP_ADD) &&
1108 (vp->operator != T_OP_SUB) &&
1109 (vp->operator != T_OP_SET)) {
1111 radlog(L_ERR|L_CONS, "%s[%d]: Invalid operator for attribute",
1112 filename, cf_pair_lineno(cp));
1122 radlog(L_ERR|L_CONS,
1123 "%s[%d]: ERROR: update %s section cannot be empty",
1124 filename, lineno, name2);
1128 g = rad_malloc(sizeof(*g)); /* never fails */
1129 memset(g, 0, sizeof(*g));
1130 csingle = mod_grouptocallable(g);
1132 csingle->parent = parent;
1133 csingle->next = NULL;
1134 csingle->name = name2;
1135 csingle->lineno = lineno;
1136 csingle->type = MOD_UPDATE;
1138 g->grouptype = GROUPTYPE_SIMPLE;
1147 static modcallable *do_compile_modswitch(modcallable *parent,
1148 int component, CONF_SECTION *cs,
1149 const char *filename, int lineno)
1151 modcallable *csingle;
1154 component = component; /* -Wunused */
1156 if (!cf_section_name2(cs)) {
1157 radlog(L_ERR|L_CONS,
1158 "%s[%d] Require variable to switch over for 'switch'.\n",
1164 * Walk through the children of the switch section,
1165 * ensuring that they're all 'case' statements
1167 for (ci=cf_item_find_next(cs, NULL);
1169 ci=cf_item_find_next(cs, ci)) {
1170 CONF_SECTION *subcs;
1171 const char *name1, *name2;
1173 if (!cf_item_is_section(ci)) {
1174 radlog(L_ERR|L_CONS,
1175 "%s[%d]: \"switch\" sections can only have \"case\" subsections",
1177 cf_pair_lineno(cf_itemtopair(ci)));
1181 subcs = cf_itemtosection(ci); /* can't return NULL */
1182 name1 = cf_section_name1(subcs);
1184 if (strcmp(name1, "case") != 0) {
1185 radlog(L_ERR|L_CONS,
1186 "%s[%d]: \"switch\" sections can only have \"case\" subsections",
1188 cf_section_lineno(cf_itemtosection(ci)));
1192 name2 = cf_section_name2(subcs);
1194 radlog(L_ERR|L_CONS,
1195 "%s[%d]: \"case\" sections must have a name",
1197 cf_section_lineno(cf_itemtosection(ci)));
1202 csingle= do_compile_modgroup(parent, component, cs, filename,
1203 GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1204 if (!csingle) return NULL;
1205 csingle->type = MOD_SWITCH;
1211 * Compile one entry of a module call.
1213 static modcallable *do_compile_modsingle(modcallable *parent,
1214 int component, CONF_ITEM *ci,
1215 const char *filename, int grouptype,
1216 const char **modname)
1219 const char *modrefname;
1221 modcallable *csingle;
1222 module_instance_t *this;
1223 CONF_SECTION *cs, *subcs;
1225 if (cf_item_is_section(ci)) {
1226 cs = cf_itemtosection(ci);
1227 const char *name2 = cf_section_name2(cs);
1229 lineno = cf_section_lineno(cs);
1230 modrefname = cf_section_name1(cs);
1231 if (!name2) name2 = "_UnNamedGroup";
1234 * group{}, redundant{}, or append{} may appear
1235 * where a single module instance was expected.
1236 * In that case, we hand it off to
1239 if (strcmp(modrefname, "group") == 0) {
1241 return do_compile_modgroup(parent, component, cs,
1246 } else if (strcmp(modrefname, "redundant") == 0) {
1248 return do_compile_modgroup(parent, component, cs,
1250 GROUPTYPE_REDUNDANT,
1253 } else if (strcmp(modrefname, "append") == 0) {
1255 return do_compile_modgroup(parent, component, cs,
1260 } else if (strcmp(modrefname, "load-balance") == 0) {
1262 csingle= do_compile_modgroup(parent, component, cs,
1266 if (!csingle) return NULL;
1267 csingle->type = MOD_LOAD_BALANCE;
1270 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1272 csingle= do_compile_modgroup(parent, component, cs,
1274 GROUPTYPE_REDUNDANT,
1276 if (!csingle) return NULL;
1277 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1280 } else if (strcmp(modrefname, "if") == 0) {
1281 if (!cf_section_name2(cs)) {
1282 radlog(L_ERR|L_CONS,
1283 "%s[%d]: 'if' without condition.\n",
1289 csingle= do_compile_modgroup(parent, component, cs,
1293 if (!csingle) return NULL;
1294 csingle->type = MOD_IF;
1296 if (!radius_evaluate_condition(NULL, 0, modname,
1298 modcallable_free(&csingle);
1305 } else if (strcmp(modrefname, "elsif") == 0) {
1307 ((parent->type == MOD_LOAD_BALANCE) ||
1308 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1309 radlog(L_ERR|L_CONS,
1310 "%s[%d] 'elsif' cannot be used in this section section.\n",
1315 if (!cf_section_name2(cs)) {
1316 radlog(L_ERR|L_CONS,
1317 "%s[%d] 'elsif' without condition.\n",
1323 csingle= do_compile_modgroup(parent, component, cs,
1327 if (!csingle) return NULL;
1328 csingle->type = MOD_ELSIF;
1330 if (!radius_evaluate_condition(NULL, 0, modname,
1332 modcallable_free(&csingle);
1339 } else if (strcmp(modrefname, "else") == 0) {
1341 ((parent->type == MOD_LOAD_BALANCE) ||
1342 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1343 radlog(L_ERR|L_CONS,
1344 "%s[%d] 'else' cannot be used in this section section.\n",
1349 if (cf_section_name2(cs)) {
1350 radlog(L_ERR|L_CONS,
1351 "%s[%d] Cannot have conditions on 'else'.\n",
1357 csingle= do_compile_modgroup(parent, component, cs,
1361 if (!csingle) return NULL;
1362 csingle->type = MOD_ELSE;
1365 } else if (strcmp(modrefname, "update") == 0) {
1368 csingle = do_compile_modupdate(parent, component, cs,
1371 if (!csingle) return NULL;
1375 } else if (strcmp(modrefname, "switch") == 0) {
1378 csingle = do_compile_modswitch(parent, component, cs,
1380 if (!csingle) return NULL;
1384 } else if (strcmp(modrefname, "case") == 0) {
1390 * FIXME: How to tell that the parent can only
1391 * be a "switch" statement?
1394 radlog(L_ERR, "%s[%d]: \"case\" statements may only appear within a \"switch\" section",
1399 csingle= do_compile_modgroup(parent, component, cs,
1403 if (!csingle) return NULL;
1404 csingle->type = MOD_CASE;
1407 * Set all of it's codes to return, so that
1408 * when we pick a 'case' statement, we don't
1409 * fall through to processing the next one.
1411 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1412 csingle->actions[i] = MOD_ACTION_RETURN;
1419 * Else it's a module reference, with updated return
1423 CONF_PAIR *cp = cf_itemtopair(ci);
1424 lineno = cf_pair_lineno(cp);
1425 modrefname = cf_pair_attr(cp);
1429 * See if the module is a virtual one. If so, return that,
1430 * rather than doing anything here.
1432 if (((cs = cf_section_find("instantiate")) != NULL) &&
1433 (subcs = cf_section_sub_find_name2(cs, NULL, modrefname)) != NULL) {
1434 DEBUG2(" Module: Loading virtual module %s", modrefname);
1437 * As it's sole configuration, the
1438 * virtual module takes a section which
1441 return do_compile_modsingle(parent,
1443 cf_sectiontoitem(subcs),
1450 * Not a virtual module. It must be a real module.
1452 this = find_module_instance(cf_section_find("modules"), modrefname);
1455 radlog(L_ERR|L_CONS, "%s[%d] Failed to find module \"%s\".", filename,
1456 lineno, modrefname);
1461 * We know it's all OK, allocate the structures, and fill
1464 single = rad_malloc(sizeof(*single));
1465 memset(single, 0, sizeof(*single));
1466 csingle = mod_singletocallable(single);
1467 csingle->parent = parent;
1468 csingle->next = NULL;
1469 csingle->lineno = lineno;
1470 memcpy(csingle->actions, defaultactions[component][grouptype],
1471 sizeof csingle->actions);
1472 rad_assert(modrefname != NULL);
1473 csingle->name = modrefname;
1474 csingle->type = MOD_SINGLE;
1477 * Singles can override the actions, virtual modules cannot.
1479 * FIXME: We may want to re-visit how to do this...
1480 * maybe a csingle as a ref?
1482 if (cf_item_is_section(ci)) {
1484 const char *attr, *value;
1486 cs = cf_itemtosection(ci);
1488 for (ci=cf_item_find_next(cs, NULL);
1490 ci=cf_item_find_next(cs, ci)) {
1492 if (cf_item_is_section(ci)) {
1493 radlog(L_ERR|L_CONS,
1494 "%s[%d] Subsection of module instance call "
1495 "not allowed\n", filename,
1496 cf_section_lineno(cf_itemtosection(ci)));
1497 modcallable_free(&csingle);
1501 cp = cf_itemtopair(ci);
1502 attr = cf_pair_attr(cp);
1503 value = cf_pair_value(cp);
1504 lineno = cf_pair_lineno(cp);
1506 if (!compile_action(csingle, attr, value, filename,
1508 modcallable_free(&csingle);
1515 * Bail out if the module in question does not supply the
1518 if (!this->entry->module->methods[component]) {
1519 radlog(L_ERR|L_CONS,
1520 "%s[%d]: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
1521 filename, lineno, this->entry->module->name,
1522 comp2str[component]);
1523 modcallable_free(&csingle);
1527 single->modinst = this;
1528 *modname = this->entry->module->name;
1532 modcallable *compile_modsingle(modcallable *parent,
1533 int component, CONF_ITEM *ci,
1534 const char *filename, const char **modname)
1536 modcallable *ret = do_compile_modsingle(parent, component, ci,
1540 dump_tree(component, ret);
1546 * Internal compile group code.
1548 static modcallable *do_compile_modgroup(modcallable *parent,
1549 int component, CONF_SECTION *cs,
1550 const char *filename, int grouptype,
1551 int parentgrouptype)
1558 g = rad_malloc(sizeof(*g));
1559 memset(g, 0, sizeof(*g));
1560 g->grouptype = grouptype;
1562 c = mod_grouptocallable(g);
1565 c->lineno = cf_section_lineno(cs);
1566 memset(c->actions, 0, sizeof(c->actions));
1569 * Remember the name for printing, etc.
1571 * FIXME: We may also want to put the names into a
1572 * rbtree, so that groups can reference each other...
1574 c->name = cf_section_name2(cs);
1575 if (!c->name) c->name = "";
1576 c->type = MOD_GROUP;
1580 * Loop over the children of this group.
1582 for (ci=cf_item_find_next(cs, NULL);
1584 ci=cf_item_find_next(cs, ci)) {
1587 * Sections are references to other groups, or
1588 * to modules with updated return codes.
1590 if (cf_item_is_section(ci)) {
1591 const char *junk = NULL;
1592 modcallable *single;
1594 CONF_SECTION *subcs = cf_itemtosection(ci);
1596 lineno = cf_section_lineno(subcs);
1598 single = do_compile_modsingle(c, component, ci,
1602 radlog(L_ERR|L_CONS,
1603 "%s[%d] Failed to parse \"%s\" subsection.\n",
1605 cf_section_name1(subcs));
1606 modcallable_free(&c);
1609 add_child(g, single);
1612 const char *attr, *value;
1613 CONF_PAIR *cp = cf_itemtopair(ci);
1616 attr = cf_pair_attr(cp);
1617 value = cf_pair_value(cp);
1618 lineno = cf_pair_lineno(cp);
1621 * A CONF_PAIR is either a module
1622 * instance with no actions
1625 if (value[0] == 0) {
1626 modcallable *single;
1627 const char *junk = NULL;
1629 single = do_compile_modsingle(c,
1636 radlog(L_ERR|L_CONS,
1637 "%s[%d] Failed to parse \"%s\" entry.\n",
1638 filename, lineno, attr);
1639 modcallable_free(&c);
1642 add_child(g, single);
1645 * Or a module instance with action.
1647 } else if (!compile_action(c, attr, value, filename,
1649 modcallable_free(&c);
1651 } /* else it worked */
1656 * Set the default actions, if they haven't already been
1659 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1660 if (!c->actions[i]) {
1661 c->actions[i] = defaultactions[component][parentgrouptype][i];
1666 * FIXME: If there are no children, return NULL?
1668 return mod_grouptocallable(g);
1671 modcallable *compile_modgroup(modcallable *parent,
1672 int component, CONF_SECTION *cs,
1673 const char *filename)
1675 modcallable *ret = do_compile_modgroup(parent, component, cs, filename,
1678 dump_tree(component, ret);
1682 void add_to_modcallable(modcallable **parent, modcallable *this,
1683 int component, const char *name)
1687 rad_assert(this != NULL);
1689 if (*parent == NULL) {
1692 g = rad_malloc(sizeof *g);
1693 memset(g, 0, sizeof(*g));
1694 g->grouptype = GROUPTYPE_SIMPLE;
1695 c = mod_grouptocallable(g);
1698 defaultactions[component][GROUPTYPE_SIMPLE],
1699 sizeof(c->actions));
1700 rad_assert(name != NULL);
1702 c->type = MOD_GROUP;
1705 *parent = mod_grouptocallable(g);
1707 g = mod_callabletogroup(*parent);
1713 void modcallable_free(modcallable **pc)
1715 modcallable *c, *loop, *next;
1717 if (c->type != MOD_SINGLE) {
1718 modgroup *g = mod_callabletogroup(c);
1720 for(loop = g->children;
1724 modcallable_free(&loop);