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>
31 /* mutually-recursive static functions need a prototype up front */
32 static modcallable *do_compile_modgroup(modcallable *,
33 int, CONF_SECTION *, const char *,
36 /* Actions may be a positive integer (the highest one returned in the group
37 * will be returned), or the keyword "return", represented here by
38 * MOD_ACTION_RETURN, to cause an immediate return.
39 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
40 * to cause an immediate reject. */
41 #define MOD_ACTION_RETURN (-1)
42 #define MOD_ACTION_REJECT (-2)
44 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
45 * explanation of what they are all about, see ../../doc/README.failover */
48 struct modcallable *next;
51 int actions[RLM_MODULE_NUMCODES];
52 enum { MOD_SINGLE, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE, MOD_IF, MOD_ELSE, MOD_ELSIF } type;
55 #define GROUPTYPE_SIMPLE 0
56 #define GROUPTYPE_REDUNDANT 1
57 #define GROUPTYPE_APPEND 2
58 #define GROUPTYPE_COUNT 3
61 modcallable mc; /* self */
62 int grouptype; /* after mc */
63 modcallable *children;
68 module_instance_t *modinst;
71 static const LRAD_NAME_NUMBER grouptype_table[] = {
72 { "", GROUPTYPE_SIMPLE },
73 { "redundant ", GROUPTYPE_REDUNDANT },
74 { "append ", GROUPTYPE_APPEND },
78 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
79 * so we often want to go back and forth between them. */
80 static modsingle *mod_callabletosingle(modcallable *p)
82 rad_assert(p->type==MOD_SINGLE);
83 return (modsingle *)p;
85 static modgroup *mod_callabletogroup(modcallable *p)
87 rad_assert((p->type==MOD_GROUP) || /* this is getting silly... */
88 (p->type==MOD_LOAD_BALANCE) ||
90 (p->type==MOD_ELSE) ||
91 (p->type==MOD_ELSIF) ||
92 (p->type==MOD_REDUNDANT_LOAD_BALANCE));
95 static modcallable *mod_singletocallable(modsingle *p)
97 return (modcallable *)p;
99 static modcallable *mod_grouptocallable(modgroup *p)
101 return (modcallable *)p;
104 /* modgroups are grown by adding a modcallable to the end */
105 static void add_child(modgroup *g, modcallable *c)
107 modcallable **head = &g->children;
108 modcallable *node = *head;
109 modcallable **last = head;
118 rad_assert(c->next == NULL);
120 c->parent = mod_grouptocallable(g);
123 /* Here's where we recognize all of our keywords: first the rcodes, then the
125 static const LRAD_NAME_NUMBER rcode_table[] = {
126 { "reject", RLM_MODULE_REJECT },
127 { "fail", RLM_MODULE_FAIL },
128 { "ok", RLM_MODULE_OK },
129 { "handled", RLM_MODULE_HANDLED },
130 { "invalid", RLM_MODULE_INVALID },
131 { "userlock", RLM_MODULE_USERLOCK },
132 { "notfound", RLM_MODULE_NOTFOUND },
133 { "noop", RLM_MODULE_NOOP },
134 { "updated", RLM_MODULE_UPDATED },
140 * Compile action && rcode for later use.
142 static int compile_action(modcallable *c, const char *attr, const char *value,
143 const char *filename, int lineno)
147 if (!strcasecmp(value, "return"))
148 action = MOD_ACTION_RETURN;
150 else if (!strcasecmp(value, "reject"))
151 action = MOD_ACTION_REJECT;
153 else if (strspn(value, "0123456789")==strlen(value)) {
154 action = atoi(value);
157 * Don't allow priority zero, for future use.
159 if (action == 0) return 0;
162 "%s[%d] Unknown action '%s'.\n",
163 filename, lineno, value);
167 if (strcasecmp(attr, "default") != 0) {
170 rcode = lrad_str2int(rcode_table, attr, -1);
173 "%s[%d] Unknown module rcode '%s'.\n",
174 filename, lineno, attr);
177 c->actions[rcode] = action;
179 } else { /* set all unset values to the default */
182 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
183 if (!c->actions[i]) c->actions[i] = action;
190 /* Some short names for debugging output */
191 static const char * const comp2str[] = {
202 #ifdef HAVE_PTHREAD_H
204 * Lock the mutex for the module
206 static void safe_lock(module_instance_t *instance)
209 pthread_mutex_lock(instance->mutex);
213 * Unlock the mutex for the module
215 static void safe_unlock(module_instance_t *instance)
218 pthread_mutex_unlock(instance->mutex);
222 * No threads: these functions become NULL's.
224 #define safe_lock(foo)
225 #define safe_unlock(foo)
228 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
231 int myresult = default_result;
233 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
234 comp2str[component], sp->modinst->name,
235 sp->modinst->entry->name, request->number);
236 safe_lock(sp->modinst);
239 * For logging unresponsive children.
241 request->module = sp->modinst->name;
243 myresult = sp->modinst->entry->module->methods[component](
244 sp->modinst->insthandle, request);
246 request->module = "<server-core>";
247 safe_unlock(sp->modinst);
248 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
249 comp2str[component], sp->modinst->name,
250 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 */
267 static const char *group_name[] = {
270 "load-balance group",
271 "redundant-load-balance group",
277 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
279 #define MODCALL_STACK_MAX (32)
282 * Don't call the modules recursively. Instead, do them
283 * iteratively, and manage the call stack ourselves.
285 typedef struct modcall_stack {
288 int priority[MODCALL_STACK_MAX];
289 int result[MODCALL_STACK_MAX];
290 modcallable *children[MODCALL_STACK_MAX];
291 modcallable *start[MODCALL_STACK_MAX];
296 * Call a module, iteratively, with a local stack, rather than
297 * recursively. What did Paul Graham say about Lisp...?
299 int modcall(int component, modcallable *c, REQUEST *request)
303 modcallable *parent, *child;
305 int if_taken, was_if;
309 if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
310 return RLM_MODULE_FAIL;
314 return default_component_results[component];
317 stack.priority[0] = 0;
318 stack.children[0] = c;
319 myresult = stack.result[0] = default_component_results[component];
320 was_if = if_taken = FALSE;
324 * A module has taken too long to process the request,
325 * and we've been told to stop processing it.
327 if (request->master_state == REQUEST_STOP_PROCESSING) {
328 myresult = RLM_MODULE_FAIL;
332 child = stack.children[stack.pointer];
333 rad_assert(child != NULL);
334 parent = child->parent;
336 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
337 if (!was_if) { /* error */
338 DEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
339 stack.pointer + 1, modcall_spaces,
340 group_name[child->type],
345 DEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
346 stack.pointer + 1, modcall_spaces,
347 group_name[child->type],
354 * "if", and the requested action wasn't the
355 * proper return code, skip the group.
357 if (((child->type == MOD_IF) || (child->type == MOD_ELSIF)) &&
358 !child->actions[myresult]) {
359 DEBUG2("%.*s ... skipping %s \"%s\" for request %d, return code was %s",
360 stack.pointer + 1, modcall_spaces,
361 group_name[child->type],
362 child->name, request->number,
363 lrad_int2str(rcode_table, myresult, "??"));
364 stack.children[stack.pointer] = NULL;
368 } /* else process it, as a simple group */
371 * Child is a group that has children of it's own.
373 if (child->type != MOD_SINGLE) {
376 modgroup *g = mod_callabletogroup(child);
381 * Catastrophic error. This SHOULD have
382 * been caught when we were reading in the
387 if (stack.pointer >= MODCALL_STACK_MAX) {
388 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
392 stack.priority[stack.pointer] = 0;
393 stack.result[stack.pointer] = default_component_results[component];
394 switch (child->type) {
399 stack.children[stack.pointer] = g->children;
403 * See the "camel book" for why
406 * If (rand(0..n) < 1), pick the
407 * current realm. We add a scale
408 * factor of 65536, to avoid
411 case MOD_LOAD_BALANCE:
412 case MOD_REDUNDANT_LOAD_BALANCE:
414 for(p = g->children; p; p = p->next) {
423 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
427 stack.children[stack.pointer] = q;
431 exit(1); /* internal sanity check failure */
436 stack.start[stack.pointer] = stack.children[stack.pointer];
438 DEBUG2("%.*s- entering %s %s",
439 stack.pointer, modcall_spaces,
440 group_name[child->type], child->name);
443 * Catch the special case of a NULL group.
445 if (!stack.children[stack.pointer]) {
447 * Print message for NULL group
449 DEBUG2("%.*s- %s returns %s",
450 stack.pointer + 1, modcall_spaces,
452 lrad_int2str(rcode_table,
453 stack.result[stack.pointer],
459 * The child may be a group, so we want to
460 * recurse into it's children, rather than
461 * falling through to the code below.
467 * Process a stand-alone child, and fall through
468 * to dealing with it's parent.
470 sp = mod_callabletosingle(child);
472 myresult = call_modsingle(component, sp, request,
473 default_component_results[component]);
474 DEBUG2("%.*s[%s] returns %s",
475 stack.pointer + 1, modcall_spaces,
477 lrad_int2str(rcode_table, myresult, "??"));
481 * FIXME: Allow modules to push a modcallable
482 * onto this stack. This should simplify
483 * configuration a LOT!
485 * Once we do that, we can't do load-time
486 * checking of the maximum stack depth, and we've
487 * got to cache the stack pointer before storing
490 * Also, if the stack changed, we need to set
491 * children[ptr] to NULL, and process the next
492 * entry on the stack, rather than falling
493 * through to finalize the processing of this
496 * Don't put "myresult" on the stack here,
497 * we have to do so with priority.
501 * We roll back up the stack at this point.
505 * The child's action says return. Do so.
507 if (child->actions[myresult] == MOD_ACTION_RETURN) {
508 stack.result[stack.pointer] = myresult;
509 stack.children[stack.pointer] = NULL;
514 * If "reject", break out of the loop and return
517 if (child->actions[myresult] == MOD_ACTION_REJECT) {
518 stack.children[stack.pointer] = NULL;
519 stack.result[stack.pointer] = RLM_MODULE_REJECT;
524 * Otherwise, the action is a number, the
525 * preference level of this return code. If no
526 * higher preference has been seen yet, remember
529 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
530 stack.result[stack.pointer] = myresult;
531 stack.priority[stack.pointer] = child->actions[myresult];
535 * No parent, we must be done.
538 rad_assert(stack.pointer == 0);
539 myresult = stack.result[0];
543 rad_assert(child != NULL);
546 * Go to the "next" child, whatever that is.
548 switch (parent->type) {
553 stack.children[stack.pointer] = child->next;
556 case MOD_LOAD_BALANCE:
557 stack.children[stack.pointer] = NULL;
560 case MOD_REDUNDANT_LOAD_BALANCE:
562 stack.children[stack.pointer] = child->next;
564 modgroup *g = mod_callabletogroup(parent);
566 stack.children[stack.pointer] = g->children;
568 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
569 stack.children[stack.pointer] = NULL;
577 * No child, we're done this group, and we return
578 * "myresult" to the caller by pushing it back up
581 if (!stack.children[stack.pointer]) {
583 rad_assert(stack.pointer > 0);
584 myresult = stack.result[stack.pointer];
587 DEBUG2("%.*s- %s %s returns %s",
588 stack.pointer + 1, modcall_spaces,
589 group_name[parent->type], parent->name,
590 lrad_int2str(rcode_table, myresult, "??"));
592 if (stack.pointer == 0) break;
594 if ((parent->type == MOD_IF) ||
595 (parent->type == MOD_ELSIF)) {
596 if_taken = was_if = TRUE;
598 if_taken = was_if = FALSE;
604 child = stack.children[stack.pointer];
605 parent = child->parent;
609 } /* loop until done */
616 static const char *action2str(int action)
619 if(action==MOD_ACTION_RETURN)
621 if(action==MOD_ACTION_REJECT)
623 snprintf(buf, sizeof buf, "%d", action);
627 /* If you suspect a bug in the parser, you'll want to use these dump
628 * functions. dump_tree should reproduce a whole tree exactly as it was found
629 * in radiusd.conf, but in long form (all actions explicitly defined) */
630 static void dump_mc(modcallable *c, int indent)
634 if(c->type==MOD_SINGLE) {
635 modsingle *single = mod_callabletosingle(c);
636 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
637 single->modinst->name);
639 modgroup *g = mod_callabletogroup(c);
641 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
642 group_name[c->type]);
643 for(p = g->children;p;p = p->next)
644 dump_mc(p, indent+1);
647 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
648 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
649 lrad_int2str(rcode_table, i, "??"),
650 action2str(c->actions[i]));
653 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
656 static void dump_tree(int comp, modcallable *c)
658 DEBUG("[%s]", comp2str[comp]);
662 #define dump_tree(a, b)
665 /* These are the default actions. For each component, the group{} block
666 * behaves like the code from the old module_*() function. redundant{} and
667 * append{} are based on my guesses of what they will be used for. --Pac. */
669 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
675 MOD_ACTION_RETURN, /* reject */
677 MOD_ACTION_RETURN, /* ok */
678 MOD_ACTION_RETURN, /* handled */
680 MOD_ACTION_RETURN, /* userlock */
681 MOD_ACTION_RETURN, /* notfound */
687 MOD_ACTION_RETURN, /* reject */
689 MOD_ACTION_RETURN, /* ok */
690 MOD_ACTION_RETURN, /* handled */
691 MOD_ACTION_RETURN, /* invalid */
692 MOD_ACTION_RETURN, /* userlock */
693 MOD_ACTION_RETURN, /* notfound */
694 MOD_ACTION_RETURN, /* noop */
695 MOD_ACTION_RETURN /* updated */
699 MOD_ACTION_RETURN, /* reject */
701 MOD_ACTION_RETURN, /* ok */
702 MOD_ACTION_RETURN, /* handled */
703 MOD_ACTION_RETURN, /* invalid */
704 MOD_ACTION_RETURN, /* userlock */
706 MOD_ACTION_RETURN, /* noop */
707 MOD_ACTION_RETURN /* updated */
714 MOD_ACTION_RETURN, /* reject */
715 MOD_ACTION_RETURN, /* fail */
717 MOD_ACTION_RETURN, /* handled */
718 MOD_ACTION_RETURN, /* invalid */
719 MOD_ACTION_RETURN, /* userlock */
726 MOD_ACTION_RETURN, /* reject */
728 MOD_ACTION_RETURN, /* ok */
729 MOD_ACTION_RETURN, /* handled */
730 MOD_ACTION_RETURN, /* invalid */
731 MOD_ACTION_RETURN, /* userlock */
732 MOD_ACTION_RETURN, /* notfound */
733 MOD_ACTION_RETURN, /* noop */
734 MOD_ACTION_RETURN /* updated */
738 MOD_ACTION_RETURN, /* reject */
740 MOD_ACTION_RETURN, /* ok */
741 MOD_ACTION_RETURN, /* handled */
742 MOD_ACTION_RETURN, /* invalid */
743 MOD_ACTION_RETURN, /* userlock */
745 MOD_ACTION_RETURN, /* noop */
746 MOD_ACTION_RETURN /* updated */
753 MOD_ACTION_RETURN, /* reject */
754 MOD_ACTION_RETURN, /* fail */
756 MOD_ACTION_RETURN, /* handled */
757 MOD_ACTION_RETURN, /* invalid */
758 MOD_ACTION_RETURN, /* userlock */
759 MOD_ACTION_RETURN, /* notfound */
765 MOD_ACTION_RETURN, /* reject */
767 MOD_ACTION_RETURN, /* ok */
768 MOD_ACTION_RETURN, /* handled */
769 MOD_ACTION_RETURN, /* invalid */
770 MOD_ACTION_RETURN, /* userlock */
771 MOD_ACTION_RETURN, /* notfound */
772 MOD_ACTION_RETURN, /* noop */
773 MOD_ACTION_RETURN /* updated */
777 MOD_ACTION_RETURN, /* reject */
779 MOD_ACTION_RETURN, /* ok */
780 MOD_ACTION_RETURN, /* handled */
781 MOD_ACTION_RETURN, /* invalid */
782 MOD_ACTION_RETURN, /* userlock */
784 MOD_ACTION_RETURN, /* noop */
785 MOD_ACTION_RETURN /* updated */
792 MOD_ACTION_RETURN, /* reject */
793 MOD_ACTION_RETURN, /* fail */
795 MOD_ACTION_RETURN, /* handled */
796 MOD_ACTION_RETURN, /* invalid */
797 MOD_ACTION_RETURN, /* userlock */
798 MOD_ACTION_RETURN, /* notfound */
806 MOD_ACTION_RETURN, /* ok */
807 MOD_ACTION_RETURN, /* handled */
816 MOD_ACTION_RETURN, /* reject */
818 MOD_ACTION_RETURN, /* ok */
819 MOD_ACTION_RETURN, /* handled */
820 MOD_ACTION_RETURN, /* invalid */
821 MOD_ACTION_RETURN, /* userlock */
823 MOD_ACTION_RETURN, /* noop */
824 MOD_ACTION_RETURN /* updated */
831 MOD_ACTION_RETURN, /* reject */
833 MOD_ACTION_RETURN, /* ok */
834 MOD_ACTION_RETURN, /* handled */
835 MOD_ACTION_RETURN, /* invalid */
836 MOD_ACTION_RETURN, /* userlock */
837 MOD_ACTION_RETURN, /* notfound */
838 MOD_ACTION_RETURN, /* noop */
839 MOD_ACTION_RETURN /* updated */
843 MOD_ACTION_RETURN, /* reject */
845 MOD_ACTION_RETURN, /* ok */
846 MOD_ACTION_RETURN, /* handled */
847 MOD_ACTION_RETURN, /* invalid */
848 MOD_ACTION_RETURN, /* userlock */
849 MOD_ACTION_RETURN, /* notfound */
850 MOD_ACTION_RETURN, /* noop */
851 MOD_ACTION_RETURN /* updated */
855 MOD_ACTION_RETURN, /* reject */
857 MOD_ACTION_RETURN, /* ok */
858 MOD_ACTION_RETURN, /* handled */
859 MOD_ACTION_RETURN, /* invalid */
860 MOD_ACTION_RETURN, /* userlock */
861 MOD_ACTION_RETURN, /* notfound */
862 MOD_ACTION_RETURN, /* noop */
863 MOD_ACTION_RETURN /* updated */
870 MOD_ACTION_RETURN, /* reject */
871 MOD_ACTION_RETURN, /* fail */
873 MOD_ACTION_RETURN, /* handled */
874 MOD_ACTION_RETURN, /* invalid */
875 MOD_ACTION_RETURN, /* userlock */
882 MOD_ACTION_RETURN, /* reject */
884 MOD_ACTION_RETURN, /* ok */
885 MOD_ACTION_RETURN, /* handled */
886 MOD_ACTION_RETURN, /* invalid */
887 MOD_ACTION_RETURN, /* userlock */
888 MOD_ACTION_RETURN, /* notfound */
889 MOD_ACTION_RETURN, /* noop */
890 MOD_ACTION_RETURN /* updated */
894 MOD_ACTION_RETURN, /* reject */
896 MOD_ACTION_RETURN, /* ok */
897 MOD_ACTION_RETURN, /* handled */
898 MOD_ACTION_RETURN, /* invalid */
899 MOD_ACTION_RETURN, /* userlock */
901 MOD_ACTION_RETURN, /* noop */
902 MOD_ACTION_RETURN /* updated */
909 MOD_ACTION_RETURN, /* reject */
910 MOD_ACTION_RETURN, /* fail */
912 MOD_ACTION_RETURN, /* handled */
913 MOD_ACTION_RETURN, /* invalid */
914 MOD_ACTION_RETURN, /* userlock */
921 MOD_ACTION_RETURN, /* reject */
923 MOD_ACTION_RETURN, /* ok */
924 MOD_ACTION_RETURN, /* handled */
925 MOD_ACTION_RETURN, /* invalid */
926 MOD_ACTION_RETURN, /* userlock */
927 MOD_ACTION_RETURN, /* notfound */
928 MOD_ACTION_RETURN, /* noop */
929 MOD_ACTION_RETURN /* updated */
933 MOD_ACTION_RETURN, /* reject */
935 MOD_ACTION_RETURN, /* ok */
936 MOD_ACTION_RETURN, /* handled */
937 MOD_ACTION_RETURN, /* invalid */
938 MOD_ACTION_RETURN, /* userlock */
940 MOD_ACTION_RETURN, /* noop */
941 MOD_ACTION_RETURN /* updated */
948 MOD_ACTION_RETURN, /* reject */
949 MOD_ACTION_RETURN, /* fail */
951 MOD_ACTION_RETURN, /* handled */
952 MOD_ACTION_RETURN, /* invalid */
953 MOD_ACTION_RETURN, /* userlock */
960 MOD_ACTION_RETURN, /* reject */
962 MOD_ACTION_RETURN, /* ok */
963 MOD_ACTION_RETURN, /* handled */
964 MOD_ACTION_RETURN, /* invalid */
965 MOD_ACTION_RETURN, /* userlock */
966 MOD_ACTION_RETURN, /* notfound */
967 MOD_ACTION_RETURN, /* noop */
968 MOD_ACTION_RETURN /* updated */
972 MOD_ACTION_RETURN, /* reject */
974 MOD_ACTION_RETURN, /* ok */
975 MOD_ACTION_RETURN, /* handled */
976 MOD_ACTION_RETURN, /* invalid */
977 MOD_ACTION_RETURN, /* userlock */
979 MOD_ACTION_RETURN, /* noop */
980 MOD_ACTION_RETURN /* updated */
986 static int condition2actions(modcallable *mc, const char *actions)
991 if (strlen(actions) >= sizeof(buffer)) {
995 memset(mc->actions, 0, sizeof(mc->actions));
998 * Copy, stripping space.
1002 if (*actions != ' ') {
1017 rcode = lrad_str2int(rcode_table, p, -1);
1018 if (rcode < 0) return -1;
1019 mc->actions[rcode] = 1;
1030 * Compile one entry of a module call.
1032 static modcallable *do_compile_modsingle(modcallable *parent,
1033 int component, CONF_ITEM *ci,
1034 const char *filename, int grouptype,
1035 const char **modname)
1038 const char *modrefname;
1040 modcallable *csingle;
1041 module_instance_t *this;
1043 if (cf_item_is_section(ci)) {
1044 CONF_SECTION *cs = cf_itemtosection(ci);
1045 const char *name2 = cf_section_name2(cs);
1047 lineno = cf_section_lineno(cs);
1048 modrefname = cf_section_name1(cs);
1049 if (!name2) name2 = "_UnNamedGroup";
1052 * group{}, redundant{}, or append{} may appear
1053 * where a single module instance was expected.
1054 * In that case, we hand it off to
1057 if (strcmp(modrefname, "group") == 0) {
1059 return do_compile_modgroup(parent, component, cs,
1063 } else if (strcmp(modrefname, "redundant") == 0) {
1065 return do_compile_modgroup(parent, component, cs,
1067 GROUPTYPE_REDUNDANT,
1069 } else if (strcmp(modrefname, "append") == 0) {
1071 return do_compile_modgroup(parent, component, cs,
1075 } else if (strcmp(modrefname, "load-balance") == 0) {
1077 csingle= do_compile_modgroup(parent, component, cs,
1081 if (!csingle) return NULL;
1082 csingle->type = MOD_LOAD_BALANCE;
1084 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1086 csingle= do_compile_modgroup(parent, component, cs,
1088 GROUPTYPE_REDUNDANT,
1090 if (!csingle) return NULL;
1091 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1093 } else if (strcmp(modrefname, "if") == 0) {
1094 if (!cf_section_name2(cs)) {
1095 radlog(L_ERR|L_CONS,
1096 "%s[%d] 'if' without condition.\n",
1102 csingle= do_compile_modgroup(parent, component, cs,
1106 if (!csingle) return NULL;
1107 csingle->type = MOD_IF;
1109 if (condition2actions(csingle, name2) < 0) {
1110 modcallable_free(&csingle);
1111 radlog(L_ERR|L_CONS,
1112 "%s[%d] Invalid module condition rcode '%s'.\n",
1113 filename, lineno, name2);
1118 } else if (strcmp(modrefname, "elsif") == 0) {
1120 ((parent->type == MOD_LOAD_BALANCE) ||
1121 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1122 radlog(L_ERR|L_CONS,
1123 "%s[%d] 'elsif' cannot be used in this section section.\n",
1128 if (!cf_section_name2(cs)) {
1129 radlog(L_ERR|L_CONS,
1130 "%s[%d] 'elsif' without condition.\n",
1136 csingle= do_compile_modgroup(parent, component, cs,
1140 if (!csingle) return NULL;
1141 csingle->type = MOD_ELSIF;
1143 if (condition2actions(csingle, name2) < 0) {
1144 modcallable_free(&csingle);
1145 radlog(L_ERR|L_CONS,
1146 "%s[%d] Invalid module condition rcode '%s'.\n",
1147 filename, lineno, name2);
1152 } else if (strcmp(modrefname, "else") == 0) {
1154 ((parent->type == MOD_LOAD_BALANCE) ||
1155 (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1156 radlog(L_ERR|L_CONS,
1157 "%s[%d] 'else' cannot be used in this section section.\n",
1162 if (cf_section_name2(cs)) {
1163 radlog(L_ERR|L_CONS,
1164 "%s[%d] Cannot have conditions on 'else'.\n",
1170 csingle= do_compile_modgroup(parent, component, cs,
1174 if (!csingle) return NULL;
1175 csingle->type = MOD_ELSE;
1180 * Else it's a module reference, with updated return
1184 CONF_PAIR *cp = cf_itemtopair(ci);
1185 lineno = cf_pair_lineno(cp);
1186 modrefname = cf_pair_attr(cp);
1190 * See if the module is a virtual one. If so, return that,
1191 * rather than doing anything here.
1193 this = find_module_instance(cf_section_find("modules"), modrefname);
1195 CONF_SECTION *cs, *subcs;
1198 * Then, look for it in the "instantiate" section.
1200 if (((subcs = cf_section_find(NULL)) != NULL) &&
1201 ((cs = cf_section_sub_find_name2(subcs, "instantiate", NULL)) != NULL)) {
1202 subcs = cf_section_sub_find_name2(cs, NULL, modrefname);
1205 * As it's sole configuration, the
1206 * virtual module takes a section which
1209 return do_compile_modsingle(parent,
1211 cf_sectiontoitem(subcs),
1220 radlog(L_ERR|L_CONS, "%s[%d] Failed to find module \"%s\".", filename,
1221 lineno, modrefname);
1226 * We know it's all OK, allocate the structures, and fill
1229 single = rad_malloc(sizeof(*single));
1230 memset(single, 0, sizeof(*single));
1231 csingle = mod_singletocallable(single);
1232 csingle->parent = parent;
1233 csingle->next = NULL;
1234 csingle->lineno = lineno;
1235 memcpy(csingle->actions, defaultactions[component][grouptype],
1236 sizeof csingle->actions);
1237 rad_assert(modrefname != NULL);
1238 csingle->name = modrefname;
1239 csingle->type = MOD_SINGLE;
1242 * Singles can override the actions, virtual modules cannot.
1244 * FIXME: We may want to re-visit how to do this...
1245 * maybe a csingle as a ref?
1247 if (cf_item_is_section(ci)) {
1248 CONF_SECTION *cs = cf_itemtosection(ci);
1250 const char *attr, *value;
1252 for (ci=cf_item_find_next(cs, NULL);
1254 ci=cf_item_find_next(cs, ci)) {
1256 if (cf_item_is_section(ci)) {
1257 radlog(L_ERR|L_CONS,
1258 "%s[%d] Subsection of module instance call "
1259 "not allowed\n", filename,
1260 cf_section_lineno(cf_itemtosection(ci)));
1261 modcallable_free(&csingle);
1265 cp = cf_itemtopair(ci);
1266 attr = cf_pair_attr(cp);
1267 value = cf_pair_value(cp);
1268 lineno = cf_pair_lineno(cp);
1270 if (!compile_action(csingle, attr, value, filename,
1272 modcallable_free(&csingle);
1279 * Bail out if the module in question does not supply the
1282 if (!this->entry->module->methods[component]) {
1283 radlog(L_ERR|L_CONS,
1284 "%s[%d]: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
1285 filename, lineno, this->entry->module->name,
1286 comp2str[component]);
1287 modcallable_free(&csingle);
1291 single->modinst = this;
1292 *modname = this->entry->module->name;
1296 modcallable *compile_modsingle(modcallable *parent,
1297 int component, CONF_ITEM *ci,
1298 const char *filename, const char **modname)
1300 modcallable *ret = do_compile_modsingle(parent, component, ci,
1304 dump_tree(component, ret);
1310 * Internal compile group code.
1312 static modcallable *do_compile_modgroup(modcallable *parent,
1313 int component, CONF_SECTION *cs,
1314 const char *filename, int grouptype,
1315 int parentgrouptype)
1322 g = rad_malloc(sizeof(*g));
1323 memset(g, 0, sizeof(*g));
1324 g->grouptype = grouptype;
1326 c = mod_grouptocallable(g);
1329 c->lineno = cf_section_lineno(cs);
1330 memset(c->actions, 0, sizeof(c->actions));
1333 * Remember the name for printing, etc.
1335 * FIXME: We may also want to put the names into a
1336 * rbtree, so that groups can reference each other...
1338 c->name = cf_section_name2(cs);
1339 if (!c->name) c->name = "";
1340 c->type = MOD_GROUP;
1344 * Loop over the children of this group.
1346 for (ci=cf_item_find_next(cs, NULL);
1348 ci=cf_item_find_next(cs, ci)) {
1351 * Sections are references to other groups, or
1352 * to modules with updated return codes.
1354 if (cf_item_is_section(ci)) {
1355 const char *junk = NULL;
1356 modcallable *single;
1358 CONF_SECTION *subcs = cf_itemtosection(ci);
1360 lineno = cf_section_lineno(subcs);
1362 single = do_compile_modsingle(c, component, ci,
1366 radlog(L_ERR|L_CONS,
1367 "%s[%d] Failed to parse \"%s\" subsection.\n",
1369 cf_section_name1(subcs));
1370 modcallable_free(&c);
1373 add_child(g, single);
1376 const char *attr, *value;
1377 CONF_PAIR *cp = cf_itemtopair(ci);
1380 attr = cf_pair_attr(cp);
1381 value = cf_pair_value(cp);
1382 lineno = cf_pair_lineno(cp);
1385 * A CONF_PAIR is either a module
1386 * instance with no actions
1389 if (value[0] == 0) {
1390 modcallable *single;
1391 const char *junk = NULL;
1393 single = do_compile_modsingle(c,
1400 radlog(L_ERR|L_CONS,
1401 "%s[%d] Failed to parse \"%s\" entry.\n",
1402 filename, lineno, attr);
1403 modcallable_free(&c);
1406 add_child(g, single);
1409 * Or a module instance with action.
1411 } else if (!compile_action(c, attr, value, filename,
1413 modcallable_free(&c);
1415 } /* else it worked */
1420 * Set the default actions, if they haven't already been
1423 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1424 if (!c->actions[i]) {
1425 c->actions[i] = defaultactions[component][parentgrouptype][i];
1430 * FIXME: If there are no children, return NULL?
1432 return mod_grouptocallable(g);
1435 modcallable *compile_modgroup(modcallable *parent,
1436 int component, CONF_SECTION *cs,
1437 const char *filename)
1439 modcallable *ret = do_compile_modgroup(parent, component, cs, filename,
1442 dump_tree(component, ret);
1446 void add_to_modcallable(modcallable **parent, modcallable *this,
1447 int component, const char *name)
1451 rad_assert(this != NULL);
1453 if (*parent == NULL) {
1456 g = rad_malloc(sizeof *g);
1457 memset(g, 0, sizeof(*g));
1458 g->grouptype = GROUPTYPE_SIMPLE;
1459 c = mod_grouptocallable(g);
1462 defaultactions[component][GROUPTYPE_SIMPLE],
1463 sizeof(c->actions));
1464 rad_assert(name != NULL);
1466 c->type = MOD_GROUP;
1469 *parent = mod_grouptocallable(g);
1471 g = mod_callabletogroup(*parent);
1477 void modcallable_free(modcallable **pc)
1479 modcallable *c, *loop, *next;
1481 if(c->type==MOD_GROUP) {
1482 for(loop = mod_callabletogroup(c)->children;
1486 modcallable_free(&loop);