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, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE, MOD_IF, MOD_ELSE, MOD_ELSIF } 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;
69 module_instance_t *modinst;
72 static const LRAD_NAME_NUMBER grouptype_table[] = {
73 { "", GROUPTYPE_SIMPLE },
74 { "redundant ", GROUPTYPE_REDUNDANT },
75 { "append ", GROUPTYPE_APPEND },
79 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
80 * so we often want to go back and forth between them. */
81 static modsingle *mod_callabletosingle(modcallable *p)
83 rad_assert(p->type==MOD_SINGLE);
84 return (modsingle *)p;
86 static modgroup *mod_callabletogroup(modcallable *p)
88 rad_assert((p->type==MOD_GROUP) || /* this is getting silly... */
89 (p->type==MOD_LOAD_BALANCE) ||
91 (p->type==MOD_ELSE) ||
92 (p->type==MOD_ELSIF) ||
93 (p->type==MOD_REDUNDANT_LOAD_BALANCE));
96 static modcallable *mod_singletocallable(modsingle *p)
98 return (modcallable *)p;
100 static modcallable *mod_grouptocallable(modgroup *p)
102 return (modcallable *)p;
105 /* modgroups are grown by adding a modcallable to the end */
106 static void add_child(modgroup *g, modcallable *c)
108 modcallable **head = &g->children;
109 modcallable *node = *head;
110 modcallable **last = head;
119 rad_assert(c->next == NULL);
121 c->parent = mod_grouptocallable(g);
124 /* Here's where we recognize all of our keywords: first the rcodes, then the
126 static const LRAD_NAME_NUMBER rcode_table[] = {
127 { "reject", RLM_MODULE_REJECT },
128 { "fail", RLM_MODULE_FAIL },
129 { "ok", RLM_MODULE_OK },
130 { "handled", RLM_MODULE_HANDLED },
131 { "invalid", RLM_MODULE_INVALID },
132 { "userlock", RLM_MODULE_USERLOCK },
133 { "notfound", RLM_MODULE_NOTFOUND },
134 { "noop", RLM_MODULE_NOOP },
135 { "updated", RLM_MODULE_UPDATED },
141 * Compile action && rcode for later use.
143 static int compile_action(modcallable *c, const char *attr, const char *value,
144 const char *filename, int lineno)
148 if (!strcasecmp(value, "return"))
149 action = MOD_ACTION_RETURN;
151 else if (!strcasecmp(value, "reject"))
152 action = MOD_ACTION_REJECT;
154 else if (strspn(value, "0123456789")==strlen(value)) {
155 action = atoi(value);
158 * Don't allow priority zero, for future use.
160 if (action == 0) return 0;
163 "%s[%d] Unknown action '%s'.\n",
164 filename, lineno, value);
168 if (strcasecmp(attr, "default") != 0) {
171 rcode = lrad_str2int(rcode_table, attr, -1);
174 "%s[%d] Unknown module rcode '%s'.\n",
175 filename, lineno, attr);
178 c->actions[rcode] = action;
180 } else { /* set all unset values to the default */
183 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
184 if (!c->actions[i]) c->actions[i] = action;
191 /* Some short names for debugging output */
192 static const char * const comp2str[] = {
203 #ifdef HAVE_PTHREAD_H
205 * Lock the mutex for the module
207 static void safe_lock(module_instance_t *instance)
210 pthread_mutex_lock(instance->mutex);
214 * Unlock the mutex for the module
216 static void safe_unlock(module_instance_t *instance)
219 pthread_mutex_unlock(instance->mutex);
223 * No threads: these functions become NULL's.
225 #define safe_lock(foo)
226 #define safe_unlock(foo)
229 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
232 int myresult = default_result;
234 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
235 comp2str[component], sp->modinst->name,
236 sp->modinst->entry->name, request->number);
237 safe_lock(sp->modinst);
240 * For logging unresponsive children.
242 request->module = sp->modinst->name;
244 myresult = sp->modinst->entry->module->methods[component](
245 sp->modinst->insthandle, request);
247 request->module = "<server-core>";
248 safe_unlock(sp->modinst);
249 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
250 comp2str[component], sp->modinst->name,
251 sp->modinst->entry->name, request->number);
256 static int default_component_results[RLM_COMPONENT_COUNT] = {
257 RLM_MODULE_REJECT, /* AUTH */
258 RLM_MODULE_NOTFOUND, /* AUTZ */
259 RLM_MODULE_NOOP, /* PREACCT */
260 RLM_MODULE_NOOP, /* ACCT */
261 RLM_MODULE_FAIL, /* SESS */
262 RLM_MODULE_NOOP, /* PRE_PROXY */
263 RLM_MODULE_NOOP, /* POST_PROXY */
264 RLM_MODULE_NOOP /* POST_AUTH */
268 static const char *group_name[] = {
271 "load-balance group",
272 "redundant-load-balance group",
278 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
280 #define MODCALL_STACK_MAX (32)
283 * Don't call the modules recursively. Instead, do them
284 * iteratively, and manage the call stack ourselves.
286 typedef struct modcall_stack {
289 int priority[MODCALL_STACK_MAX];
290 int result[MODCALL_STACK_MAX];
291 modcallable *children[MODCALL_STACK_MAX];
292 modcallable *start[MODCALL_STACK_MAX];
297 * Call a module, iteratively, with a local stack, rather than
298 * recursively. What did Paul Graham say about Lisp...?
300 int modcall(int component, modcallable *c, REQUEST *request)
304 modcallable *parent, *child;
306 int if_taken, was_if;
310 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
311 return RLM_MODULE_FAIL;
315 return default_component_results[component];
318 stack.priority[0] = 0;
319 stack.children[0] = c;
320 myresult = stack.result[0] = default_component_results[component];
321 was_if = if_taken = FALSE;
325 * A module has taken too long to process the request,
326 * and we've been told to stop processing it.
328 if (request->master_state == REQUEST_STOP_PROCESSING) {
329 myresult = RLM_MODULE_FAIL;
333 child = stack.children[stack.pointer];
334 rad_assert(child != NULL);
335 parent = child->parent;
337 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
338 if (!was_if) { /* error */
339 DEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
340 stack.pointer + 1, modcall_spaces,
341 group_name[child->type],
346 DEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
347 stack.pointer + 1, modcall_spaces,
348 group_name[child->type],
355 * "if" or "elsif". Evaluate the condition.
357 if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {
358 int condition = TRUE;
359 const char *p = child->name;
361 DEBUG2("%.*s? %s %s",
362 stack.pointer + 1, modcall_spaces,
363 (child->type == MOD_IF) ? "if" : "elsif",
366 if (radius_evaluate_condition(request, 0, &p,
368 DEBUG2("%.*s? %s %s -> %s",
369 stack.pointer + 1, modcall_spaces,
370 (child->type == MOD_IF) ? "if" : "elsif",
371 child->name, (condition != FALSE) ? "TRUE" : "FALSE");
374 * This should never happen, the
375 * condition is checked when the
376 * module section is loaded.
382 stack.children[stack.pointer] = NULL;
386 } /* else process it as a simple group */
390 * Child is a group that has children of it's own.
392 if (child->type != MOD_SINGLE) {
395 modgroup *g = mod_callabletogroup(child);
400 * Catastrophic error. This SHOULD have
401 * been caught when we were reading in the
406 if (stack.pointer >= MODCALL_STACK_MAX) {
407 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
411 stack.priority[stack.pointer] = 0;
412 stack.result[stack.pointer] = default_component_results[component];
413 switch (child->type) {
418 stack.children[stack.pointer] = g->children;
422 * See the "camel book" for why
425 * If (rand(0..n) < 1), pick the
426 * current realm. We add a scale
427 * factor of 65536, to avoid
430 case MOD_LOAD_BALANCE:
431 case MOD_REDUNDANT_LOAD_BALANCE:
433 for(p = g->children; p; p = p->next) {
442 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
446 stack.children[stack.pointer] = q;
450 exit(1); /* internal sanity check failure */
455 stack.start[stack.pointer] = stack.children[stack.pointer];
457 DEBUG2("%.*s- entering %s %s",
458 stack.pointer, modcall_spaces,
459 group_name[child->type], child->name);
462 * Catch the special case of a NULL group.
464 if (!stack.children[stack.pointer]) {
466 * Print message for NULL group
468 DEBUG2("%.*s- %s returns %s",
469 stack.pointer + 1, modcall_spaces,
471 lrad_int2str(rcode_table,
472 stack.result[stack.pointer],
478 * The child may be a group, so we want to
479 * recurse into it's children, rather than
480 * falling through to the code below.
486 * Process a stand-alone child, and fall through
487 * to dealing with it's parent.
489 sp = mod_callabletosingle(child);
491 myresult = call_modsingle(component, sp, request,
492 default_component_results[component]);
493 DEBUG2("%.*s[%s] returns %s",
494 stack.pointer + 1, modcall_spaces,
496 lrad_int2str(rcode_table, myresult, "??"));
500 * FIXME: Allow modules to push a modcallable
501 * onto this stack. This should simplify
502 * configuration a LOT!
504 * Once we do that, we can't do load-time
505 * checking of the maximum stack depth, and we've
506 * got to cache the stack pointer before storing
509 * Also, if the stack changed, we need to set
510 * children[ptr] to NULL, and process the next
511 * entry on the stack, rather than falling
512 * through to finalize the processing of this
515 * Don't put "myresult" on the stack here,
516 * we have to do so with priority.
520 * We roll back up the stack at this point.
524 * The child's action says return. Do so.
526 if (child->actions[myresult] == MOD_ACTION_RETURN) {
527 stack.result[stack.pointer] = myresult;
528 stack.children[stack.pointer] = NULL;
533 * If "reject", break out of the loop and return
536 if (child->actions[myresult] == MOD_ACTION_REJECT) {
537 stack.children[stack.pointer] = NULL;
538 stack.result[stack.pointer] = RLM_MODULE_REJECT;
543 * Otherwise, the action is a number, the
544 * preference level of this return code. If no
545 * higher preference has been seen yet, remember
548 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
549 stack.result[stack.pointer] = myresult;
550 stack.priority[stack.pointer] = child->actions[myresult];
554 * No parent, we must be done.
557 rad_assert(stack.pointer == 0);
558 myresult = stack.result[0];
562 rad_assert(child != NULL);
565 * Go to the "next" child, whatever that is.
567 switch (parent->type) {
572 stack.children[stack.pointer] = child->next;
575 case MOD_LOAD_BALANCE:
576 stack.children[stack.pointer] = NULL;
579 case MOD_REDUNDANT_LOAD_BALANCE:
581 stack.children[stack.pointer] = child->next;
583 modgroup *g = mod_callabletogroup(parent);
585 stack.children[stack.pointer] = g->children;
587 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
588 stack.children[stack.pointer] = NULL;
596 * No child, we're done this group, and we return
597 * "myresult" to the caller by pushing it back up
600 if (!stack.children[stack.pointer]) {
602 rad_assert(stack.pointer > 0);
603 myresult = stack.result[stack.pointer];
606 DEBUG2("%.*s- %s %s returns %s",
607 stack.pointer + 1, modcall_spaces,
608 group_name[parent->type], parent->name,
609 lrad_int2str(rcode_table, myresult, "??"));
611 if (stack.pointer == 0) break;
613 if ((parent->type == MOD_IF) ||
614 (parent->type == MOD_ELSIF)) {
615 if_taken = was_if = TRUE;
617 if_taken = was_if = FALSE;
623 child = stack.children[stack.pointer];
624 parent = child->parent;
628 } /* loop until done */
635 static const char *action2str(int action)
638 if(action==MOD_ACTION_RETURN)
640 if(action==MOD_ACTION_REJECT)
642 snprintf(buf, sizeof buf, "%d", action);
646 /* If you suspect a bug in the parser, you'll want to use these dump
647 * functions. dump_tree should reproduce a whole tree exactly as it was found
648 * in radiusd.conf, but in long form (all actions explicitly defined) */
649 static void dump_mc(modcallable *c, int indent)
653 if(c->type==MOD_SINGLE) {
654 modsingle *single = mod_callabletosingle(c);
655 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
656 single->modinst->name);
658 modgroup *g = mod_callabletogroup(c);
660 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
661 group_name[c->type]);
662 for(p = g->children;p;p = p->next)
663 dump_mc(p, indent+1);
666 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
667 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
668 lrad_int2str(rcode_table, i, "??"),
669 action2str(c->actions[i]));
672 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
675 static void dump_tree(int comp, modcallable *c)
677 DEBUG("[%s]", comp2str[comp]);
681 #define dump_tree(a, b)
684 /* These are the default actions. For each component, the group{} block
685 * behaves like the code from the old module_*() function. redundant{} and
686 * append{} are based on my guesses of what they will be used for. --Pac. */
688 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
694 MOD_ACTION_RETURN, /* reject */
696 MOD_ACTION_RETURN, /* ok */
697 MOD_ACTION_RETURN, /* handled */
699 MOD_ACTION_RETURN, /* userlock */
700 MOD_ACTION_RETURN, /* notfound */
706 MOD_ACTION_RETURN, /* reject */
708 MOD_ACTION_RETURN, /* ok */
709 MOD_ACTION_RETURN, /* handled */
710 MOD_ACTION_RETURN, /* invalid */
711 MOD_ACTION_RETURN, /* userlock */
712 MOD_ACTION_RETURN, /* notfound */
713 MOD_ACTION_RETURN, /* noop */
714 MOD_ACTION_RETURN /* updated */
718 MOD_ACTION_RETURN, /* reject */
720 MOD_ACTION_RETURN, /* ok */
721 MOD_ACTION_RETURN, /* handled */
722 MOD_ACTION_RETURN, /* invalid */
723 MOD_ACTION_RETURN, /* userlock */
725 MOD_ACTION_RETURN, /* noop */
726 MOD_ACTION_RETURN /* updated */
733 MOD_ACTION_RETURN, /* reject */
734 MOD_ACTION_RETURN, /* fail */
736 MOD_ACTION_RETURN, /* handled */
737 MOD_ACTION_RETURN, /* invalid */
738 MOD_ACTION_RETURN, /* userlock */
745 MOD_ACTION_RETURN, /* reject */
747 MOD_ACTION_RETURN, /* ok */
748 MOD_ACTION_RETURN, /* handled */
749 MOD_ACTION_RETURN, /* invalid */
750 MOD_ACTION_RETURN, /* userlock */
751 MOD_ACTION_RETURN, /* notfound */
752 MOD_ACTION_RETURN, /* noop */
753 MOD_ACTION_RETURN /* updated */
757 MOD_ACTION_RETURN, /* reject */
759 MOD_ACTION_RETURN, /* ok */
760 MOD_ACTION_RETURN, /* handled */
761 MOD_ACTION_RETURN, /* invalid */
762 MOD_ACTION_RETURN, /* userlock */
764 MOD_ACTION_RETURN, /* noop */
765 MOD_ACTION_RETURN /* updated */
772 MOD_ACTION_RETURN, /* reject */
773 MOD_ACTION_RETURN, /* fail */
775 MOD_ACTION_RETURN, /* handled */
776 MOD_ACTION_RETURN, /* invalid */
777 MOD_ACTION_RETURN, /* userlock */
778 MOD_ACTION_RETURN, /* notfound */
784 MOD_ACTION_RETURN, /* reject */
786 MOD_ACTION_RETURN, /* ok */
787 MOD_ACTION_RETURN, /* handled */
788 MOD_ACTION_RETURN, /* invalid */
789 MOD_ACTION_RETURN, /* userlock */
790 MOD_ACTION_RETURN, /* notfound */
791 MOD_ACTION_RETURN, /* noop */
792 MOD_ACTION_RETURN /* updated */
796 MOD_ACTION_RETURN, /* reject */
798 MOD_ACTION_RETURN, /* ok */
799 MOD_ACTION_RETURN, /* handled */
800 MOD_ACTION_RETURN, /* invalid */
801 MOD_ACTION_RETURN, /* userlock */
803 MOD_ACTION_RETURN, /* noop */
804 MOD_ACTION_RETURN /* updated */
811 MOD_ACTION_RETURN, /* reject */
812 MOD_ACTION_RETURN, /* fail */
814 MOD_ACTION_RETURN, /* handled */
815 MOD_ACTION_RETURN, /* invalid */
816 MOD_ACTION_RETURN, /* userlock */
817 MOD_ACTION_RETURN, /* notfound */
825 MOD_ACTION_RETURN, /* ok */
826 MOD_ACTION_RETURN, /* handled */
835 MOD_ACTION_RETURN, /* reject */
837 MOD_ACTION_RETURN, /* ok */
838 MOD_ACTION_RETURN, /* handled */
839 MOD_ACTION_RETURN, /* invalid */
840 MOD_ACTION_RETURN, /* userlock */
842 MOD_ACTION_RETURN, /* noop */
843 MOD_ACTION_RETURN /* updated */
850 MOD_ACTION_RETURN, /* reject */
852 MOD_ACTION_RETURN, /* ok */
853 MOD_ACTION_RETURN, /* handled */
854 MOD_ACTION_RETURN, /* invalid */
855 MOD_ACTION_RETURN, /* userlock */
856 MOD_ACTION_RETURN, /* notfound */
857 MOD_ACTION_RETURN, /* noop */
858 MOD_ACTION_RETURN /* updated */
862 MOD_ACTION_RETURN, /* reject */
864 MOD_ACTION_RETURN, /* ok */
865 MOD_ACTION_RETURN, /* handled */
866 MOD_ACTION_RETURN, /* invalid */
867 MOD_ACTION_RETURN, /* userlock */
868 MOD_ACTION_RETURN, /* notfound */
869 MOD_ACTION_RETURN, /* noop */
870 MOD_ACTION_RETURN /* updated */
874 MOD_ACTION_RETURN, /* reject */
876 MOD_ACTION_RETURN, /* ok */
877 MOD_ACTION_RETURN, /* handled */
878 MOD_ACTION_RETURN, /* invalid */
879 MOD_ACTION_RETURN, /* userlock */
880 MOD_ACTION_RETURN, /* notfound */
881 MOD_ACTION_RETURN, /* noop */
882 MOD_ACTION_RETURN /* updated */
889 MOD_ACTION_RETURN, /* reject */
890 MOD_ACTION_RETURN, /* fail */
892 MOD_ACTION_RETURN, /* handled */
893 MOD_ACTION_RETURN, /* invalid */
894 MOD_ACTION_RETURN, /* userlock */
901 MOD_ACTION_RETURN, /* reject */
903 MOD_ACTION_RETURN, /* ok */
904 MOD_ACTION_RETURN, /* handled */
905 MOD_ACTION_RETURN, /* invalid */
906 MOD_ACTION_RETURN, /* userlock */
907 MOD_ACTION_RETURN, /* notfound */
908 MOD_ACTION_RETURN, /* noop */
909 MOD_ACTION_RETURN /* updated */
913 MOD_ACTION_RETURN, /* reject */
915 MOD_ACTION_RETURN, /* ok */
916 MOD_ACTION_RETURN, /* handled */
917 MOD_ACTION_RETURN, /* invalid */
918 MOD_ACTION_RETURN, /* userlock */
920 MOD_ACTION_RETURN, /* noop */
921 MOD_ACTION_RETURN /* updated */
928 MOD_ACTION_RETURN, /* reject */
929 MOD_ACTION_RETURN, /* fail */
931 MOD_ACTION_RETURN, /* handled */
932 MOD_ACTION_RETURN, /* invalid */
933 MOD_ACTION_RETURN, /* userlock */
940 MOD_ACTION_RETURN, /* reject */
942 MOD_ACTION_RETURN, /* ok */
943 MOD_ACTION_RETURN, /* handled */
944 MOD_ACTION_RETURN, /* invalid */
945 MOD_ACTION_RETURN, /* userlock */
946 MOD_ACTION_RETURN, /* notfound */
947 MOD_ACTION_RETURN, /* noop */
948 MOD_ACTION_RETURN /* updated */
952 MOD_ACTION_RETURN, /* reject */
954 MOD_ACTION_RETURN, /* ok */
955 MOD_ACTION_RETURN, /* handled */
956 MOD_ACTION_RETURN, /* invalid */
957 MOD_ACTION_RETURN, /* userlock */
959 MOD_ACTION_RETURN, /* noop */
960 MOD_ACTION_RETURN /* updated */
967 MOD_ACTION_RETURN, /* reject */
968 MOD_ACTION_RETURN, /* fail */
970 MOD_ACTION_RETURN, /* handled */
971 MOD_ACTION_RETURN, /* invalid */
972 MOD_ACTION_RETURN, /* userlock */
979 MOD_ACTION_RETURN, /* reject */
981 MOD_ACTION_RETURN, /* ok */
982 MOD_ACTION_RETURN, /* handled */
983 MOD_ACTION_RETURN, /* invalid */
984 MOD_ACTION_RETURN, /* userlock */
985 MOD_ACTION_RETURN, /* notfound */
986 MOD_ACTION_RETURN, /* noop */
987 MOD_ACTION_RETURN /* updated */
991 MOD_ACTION_RETURN, /* reject */
993 MOD_ACTION_RETURN, /* ok */
994 MOD_ACTION_RETURN, /* handled */
995 MOD_ACTION_RETURN, /* invalid */
996 MOD_ACTION_RETURN, /* userlock */
998 MOD_ACTION_RETURN, /* noop */
999 MOD_ACTION_RETURN /* updated */
1006 * Compile one entry of a module call.
1008 static modcallable *do_compile_modsingle(modcallable *parent,
1009 int component, CONF_ITEM *ci,
1010 const char *filename, int grouptype,
1011 const char **modname)
1014 const char *modrefname;
1016 modcallable *csingle;
1017 module_instance_t *this;
1018 CONF_SECTION *cs, *subcs;
1020 if (cf_item_is_section(ci)) {
1021 CONF_SECTION *cs = cf_itemtosection(ci);
1022 const char *name2 = cf_section_name2(cs);
1024 lineno = cf_section_lineno(cs);
1025 modrefname = cf_section_name1(cs);
1026 if (!name2) name2 = "_UnNamedGroup";
1029 * group{}, redundant{}, or append{} may appear
1030 * where a single module instance was expected.
1031 * In that case, we hand it off to
1034 if (strcmp(modrefname, "group") == 0) {
1036 return do_compile_modgroup(parent, component, cs,
1040 } else if (strcmp(modrefname, "redundant") == 0) {
1042 return do_compile_modgroup(parent, component, cs,
1044 GROUPTYPE_REDUNDANT,
1046 } else if (strcmp(modrefname, "append") == 0) {
1048 return do_compile_modgroup(parent, component, cs,
1052 } else if (strcmp(modrefname, "load-balance") == 0) {
1054 csingle= do_compile_modgroup(parent, component, cs,
1058 if (!csingle) return NULL;
1059 csingle->type = MOD_LOAD_BALANCE;
1061 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1063 csingle= do_compile_modgroup(parent, component, cs,
1065 GROUPTYPE_REDUNDANT,
1067 if (!csingle) return NULL;
1068 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1070 } else if (strcmp(modrefname, "if") == 0) {
1071 if (!cf_section_name2(cs)) {
1072 radlog(L_ERR|L_CONS,
1073 "%s[%d] 'if' without condition.\n",
1079 csingle= do_compile_modgroup(parent, component, cs,
1083 if (!csingle) return NULL;
1084 csingle->type = MOD_IF;
1086 if (!radius_evaluate_condition(NULL, 0, modname,
1088 modcallable_free(&csingle);
1094 } else if (strcmp(modrefname, "elsif") == 0) {
1096 ((parent->type == MOD_LOAD_BALANCE) ||
1097 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1098 radlog(L_ERR|L_CONS,
1099 "%s[%d] 'elsif' cannot be used in this section section.\n",
1104 if (!cf_section_name2(cs)) {
1105 radlog(L_ERR|L_CONS,
1106 "%s[%d] 'elsif' without condition.\n",
1112 csingle= do_compile_modgroup(parent, component, cs,
1116 if (!csingle) return NULL;
1117 csingle->type = MOD_ELSIF;
1119 if (!radius_evaluate_condition(NULL, 0, modname,
1121 modcallable_free(&csingle);
1127 } else if (strcmp(modrefname, "else") == 0) {
1129 ((parent->type == MOD_LOAD_BALANCE) ||
1130 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1131 radlog(L_ERR|L_CONS,
1132 "%s[%d] 'else' cannot be used in this section section.\n",
1137 if (cf_section_name2(cs)) {
1138 radlog(L_ERR|L_CONS,
1139 "%s[%d] Cannot have conditions on 'else'.\n",
1145 csingle= do_compile_modgroup(parent, component, cs,
1149 if (!csingle) return NULL;
1150 csingle->type = MOD_ELSE;
1155 * Else it's a module reference, with updated return
1159 CONF_PAIR *cp = cf_itemtopair(ci);
1160 lineno = cf_pair_lineno(cp);
1161 modrefname = cf_pair_attr(cp);
1165 * FIXME: If module name is "update", or stuff... add it
1166 * to the if/then/else parent for parsing at run time?
1170 * See if the module is a virtual one. If so, return that,
1171 * rather than doing anything here.
1173 if (((cs = cf_section_find("instantiate")) != NULL) &&
1174 (subcs = cf_section_sub_find_name2(cs, NULL, modrefname)) != NULL) {
1175 DEBUG2(" Module: Loading virtual module %s", modrefname);
1178 * As it's sole configuration, the
1179 * virtual module takes a section which
1182 return do_compile_modsingle(parent,
1184 cf_sectiontoitem(subcs),
1191 * Not a virtual module. It must be a real module.
1193 this = find_module_instance(cf_section_find("modules"), modrefname);
1196 radlog(L_ERR|L_CONS, "%s[%d] Failed to find module \"%s\".", filename,
1197 lineno, modrefname);
1202 * We know it's all OK, allocate the structures, and fill
1205 single = rad_malloc(sizeof(*single));
1206 memset(single, 0, sizeof(*single));
1207 csingle = mod_singletocallable(single);
1208 csingle->parent = parent;
1209 csingle->next = NULL;
1210 csingle->lineno = lineno;
1211 memcpy(csingle->actions, defaultactions[component][grouptype],
1212 sizeof csingle->actions);
1213 rad_assert(modrefname != NULL);
1214 csingle->name = modrefname;
1215 csingle->type = MOD_SINGLE;
1218 * Singles can override the actions, virtual modules cannot.
1220 * FIXME: We may want to re-visit how to do this...
1221 * maybe a csingle as a ref?
1223 if (cf_item_is_section(ci)) {
1224 CONF_SECTION *cs = cf_itemtosection(ci);
1226 const char *attr, *value;
1228 for (ci=cf_item_find_next(cs, NULL);
1230 ci=cf_item_find_next(cs, ci)) {
1232 if (cf_item_is_section(ci)) {
1233 radlog(L_ERR|L_CONS,
1234 "%s[%d] Subsection of module instance call "
1235 "not allowed\n", filename,
1236 cf_section_lineno(cf_itemtosection(ci)));
1237 modcallable_free(&csingle);
1241 cp = cf_itemtopair(ci);
1242 attr = cf_pair_attr(cp);
1243 value = cf_pair_value(cp);
1244 lineno = cf_pair_lineno(cp);
1246 if (!compile_action(csingle, attr, value, filename,
1248 modcallable_free(&csingle);
1255 * Bail out if the module in question does not supply the
1258 if (!this->entry->module->methods[component]) {
1259 radlog(L_ERR|L_CONS,
1260 "%s[%d]: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
1261 filename, lineno, this->entry->module->name,
1262 comp2str[component]);
1263 modcallable_free(&csingle);
1267 single->modinst = this;
1268 *modname = this->entry->module->name;
1272 modcallable *compile_modsingle(modcallable *parent,
1273 int component, CONF_ITEM *ci,
1274 const char *filename, const char **modname)
1276 modcallable *ret = do_compile_modsingle(parent, component, ci,
1280 dump_tree(component, ret);
1286 * Internal compile group code.
1288 static modcallable *do_compile_modgroup(modcallable *parent,
1289 int component, CONF_SECTION *cs,
1290 const char *filename, int grouptype,
1291 int parentgrouptype)
1298 g = rad_malloc(sizeof(*g));
1299 memset(g, 0, sizeof(*g));
1300 g->grouptype = grouptype;
1302 c = mod_grouptocallable(g);
1305 c->lineno = cf_section_lineno(cs);
1306 memset(c->actions, 0, sizeof(c->actions));
1309 * Remember the name for printing, etc.
1311 * FIXME: We may also want to put the names into a
1312 * rbtree, so that groups can reference each other...
1314 c->name = cf_section_name2(cs);
1315 if (!c->name) c->name = "";
1316 c->type = MOD_GROUP;
1320 * Loop over the children of this group.
1322 for (ci=cf_item_find_next(cs, NULL);
1324 ci=cf_item_find_next(cs, ci)) {
1327 * Sections are references to other groups, or
1328 * to modules with updated return codes.
1330 if (cf_item_is_section(ci)) {
1331 const char *junk = NULL;
1332 modcallable *single;
1334 CONF_SECTION *subcs = cf_itemtosection(ci);
1336 lineno = cf_section_lineno(subcs);
1338 single = do_compile_modsingle(c, component, ci,
1342 radlog(L_ERR|L_CONS,
1343 "%s[%d] Failed to parse \"%s\" subsection.\n",
1345 cf_section_name1(subcs));
1346 modcallable_free(&c);
1349 add_child(g, single);
1352 const char *attr, *value;
1353 CONF_PAIR *cp = cf_itemtopair(ci);
1356 attr = cf_pair_attr(cp);
1357 value = cf_pair_value(cp);
1358 lineno = cf_pair_lineno(cp);
1361 * A CONF_PAIR is either a module
1362 * instance with no actions
1365 if (value[0] == 0) {
1366 modcallable *single;
1367 const char *junk = NULL;
1369 single = do_compile_modsingle(c,
1376 radlog(L_ERR|L_CONS,
1377 "%s[%d] Failed to parse \"%s\" entry.\n",
1378 filename, lineno, attr);
1379 modcallable_free(&c);
1382 add_child(g, single);
1385 * Or a module instance with action.
1387 } else if (!compile_action(c, attr, value, filename,
1389 modcallable_free(&c);
1391 } /* else it worked */
1396 * Set the default actions, if they haven't already been
1399 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1400 if (!c->actions[i]) {
1401 c->actions[i] = defaultactions[component][parentgrouptype][i];
1406 * FIXME: If there are no children, return NULL?
1408 return mod_grouptocallable(g);
1411 modcallable *compile_modgroup(modcallable *parent,
1412 int component, CONF_SECTION *cs,
1413 const char *filename)
1415 modcallable *ret = do_compile_modgroup(parent, component, cs, filename,
1418 dump_tree(component, ret);
1422 void add_to_modcallable(modcallable **parent, modcallable *this,
1423 int component, const char *name)
1427 rad_assert(this != NULL);
1429 if (*parent == NULL) {
1432 g = rad_malloc(sizeof *g);
1433 memset(g, 0, sizeof(*g));
1434 g->grouptype = GROUPTYPE_SIMPLE;
1435 c = mod_grouptocallable(g);
1438 defaultactions[component][GROUPTYPE_SIMPLE],
1439 sizeof(c->actions));
1440 rad_assert(name != NULL);
1442 c->type = MOD_GROUP;
1445 *parent = mod_grouptocallable(g);
1447 g = mod_callabletogroup(*parent);
1453 void modcallable_free(modcallable **pc)
1455 modcallable *c, *loop, *next;
1457 if(c->type==MOD_GROUP) {
1458 for(loop = mod_callabletogroup(c)->children;
1462 modcallable_free(&loop);